กลไกการอ่านและเขียนส่วนประกอบของ Delphi (i)
1. บทนำเกี่ยวกับการสตรีมวัตถุ (สตรีม) และวัตถุอ่านเขียน (filers)
ในการเขียนโปรแกรมเชิงวัตถุการจัดการข้อมูลตามวัตถุจะอยู่ในตำแหน่งที่สำคัญมาก ใน Delphi วิธีการสนับสนุนของการจัดการข้อมูลตามวัตถุเป็นหนึ่งในคุณสมบัติที่สำคัญ
Delphi เป็นสภาพแวดล้อมการพัฒนาแบบบูรณาการที่รวมการออกแบบภาพเชิงวัตถุเข้ากับภาษาเชิงวัตถุ แกนกลางของ Delphi คือส่วนประกอบ ส่วนประกอบเป็นประเภทของวัตถุ แอปพลิเคชัน Delphi ถูกสร้างขึ้นโดยส่วนประกอบทั้งหมดดังนั้นการพัฒนาแอพพลิเคชั่น Delphi ที่มีประสิทธิภาพสูงจะเกี่ยวข้องกับเทคโนโลยีการจัดการข้อมูลตามวัตถุอย่างหลีกเลี่ยงไม่ได้
การจัดการข้อมูลตามวัตถุมีสองด้าน:
●ใช้วัตถุเพื่อจัดการข้อมูล
●การจัดการวัตถุข้อมูลต่าง ๆ (รวมถึงวัตถุและส่วนประกอบ)
แอตทริบิวต์ Delphi คลาสการจัดการข้อมูลตามวัตถุไปยังสตรีมวัตถุ (สตรีม) และวัตถุตัวกรอง (filers) และนำไปใช้กับทุกด้านของไลบรารีคลาสคอมโพเนนต์ภาพ (VCL) พวกเขามีฟังก์ชั่นที่หลากหลายในการจัดการวัตถุในหน่วยความจำหน่วยความจำภายนอกและทรัพยากร Windows
วัตถุสตรีมหรือที่รู้จักกันในชื่อวัตถุสตรีมมิ่งเป็นคำทั่วไปสำหรับ tstream, thandlestream, tfilestream, tmemorystream, tresourcestream และ tblobstream พวกเขาแสดงถึงความสามารถในการจัดเก็บข้อมูลบนสื่อต่าง ๆ การดำเนินการจัดการแบบนามธรรมของประเภทข้อมูลที่หลากหลาย (รวมถึงวัตถุและส่วนประกอบ) ในหน่วยความจำนอกหน่วยความจำและฟิลด์ฐานข้อมูลเป็นวิธีการวัตถุและใช้ประโยชน์จากความได้เปรียบด้านเทคโนโลยีเชิงวัตถุอย่างเต็มที่ จากนี้แอปพลิเคชันสามารถคัดลอกข้อมูลในวัตถุสตรีมต่างๆได้อย่างง่ายดาย
อ่านและเขียนวัตถุ (filers) รวมวัตถุ tfiler วัตถุ treader และวัตถุ twriter วัตถุ tfiler เป็นวัตถุพื้นฐานสำหรับการอ่านและเขียนไฟล์และการใช้งานหลักของ treader และ twriter ในแอปพลิเคชัน ทั้งวัตถุ treader และ twriter ได้รับการสืบทอดโดยตรงจากวัตถุ tfiler วัตถุ TFILER กำหนดคุณสมบัติและวิธีการพื้นฐานของวัตถุ Filer
Filer Objects ส่วนใหญ่ทำหน้าที่หลักสองฟังก์ชั่น:
●การเข้าถึงไฟล์ฟอร์มและส่วนประกอบในไฟล์ฟอร์ม
●ให้การบัฟเฟอร์ข้อมูลเพื่อเร่งการอ่านข้อมูลและการเขียน
เพื่อที่จะมีความเข้าใจในการรับรู้ของวัตถุสตรีมมิ่งและอ่านและเขียนวัตถุให้ดูตัวอย่างก่อน
a) เขียนไฟล์
ขั้นตอน TFOMR1.Writedata (ผู้ส่ง: tobject);
วาจา
FileStream: tfilestream;
MyWriter: Twriter;
ฉัน: จำนวนเต็ม
เริ่ม
fileStream: = tfilestream.create ('c: /test.txt',fmopenwrite); // สร้างวัตถุสตรีมไฟล์
MyWriter: = twriter.create (FileStream, 1024);
MyWriter.WriteListBegin;
สำหรับ i: = 0 ถึง memo1.lines.count-1 do
mywriter.writestring (memo1.lines [i]);
MyWriter.WriteListend;
filestream.seek (0, sofrombeginning);
mywriter.free;
FileStream.Free;
จบ;
b) อ่านไฟล์
ขั้นตอน tform1.readdata (ผู้ส่ง: tobject);
วาจา
FileStream: tfilestream;
MyReader: Treader;
เริ่ม
fileStream: = tfilestream.create ('c: /test.txt',fmopenread);
myReader: = trreader.create (FileStream, 1024);
MyReader.ReadListBegin;
memo1.lines.clear;
ในขณะที่ไม่ใช่ myReader.endoflist ทำ // บันทึกวิธีการของ treader: endoflist
เริ่ม
memo1.lines.add (myReader.ReadString);
จบ;
MyReader.ReadListend;
myReader.free;
FileStream.Free;
จบ;
สองกระบวนการข้างต้นเป็นกระบวนการสำหรับการเขียนและอีกกระบวนการหนึ่งสำหรับกระบวนการอ่าน กระบวนการเขียนใช้ TwRiter เพื่อบันทึกเนื้อหา (ข้อมูลข้อความ) ในบันทึกเป็นไฟล์ไบนารีที่บันทึกไว้ในดิสก์โดยใช้ TFileStream กระบวนการอ่านเป็นสิ่งที่ตรงกันข้ามกับกระบวนการเขียน การรันโปรแกรมสามารถเห็นได้ว่ากระบวนการอ่านจะคืนข้อมูลที่บันทึกไว้ในกระบวนการเขียนอย่างซื่อสัตย์
รูปต่อไปนี้อธิบายถึงความสัมพันธ์ระหว่างวัตถุข้อมูล (รวมถึงวัตถุและส่วนประกอบ) วัตถุสตรีมมิ่งและการอ่านและเขียนวัตถุ
รูป (1)
เป็นที่น่าสังเกตว่าการอ่านและเขียนวัตถุเช่นวัตถุ tfiler วัตถุ treader และวัตถุ twriter ไม่ค่อยได้รับการเรียกโดยตรงโดยนักเขียนแอปพลิเคชัน และการเขียนกลไกส่วนประกอบ
สำหรับสตรีมการสตรีมวัตถุวัสดุอ้างอิงจำนวนมากได้รับการแนะนำในรายละเอียดในขณะที่วัสดุอ้างอิงสำหรับวัตถุ tfiler วัตถุ treader และวัตถุ twriter โดยเฉพาะอย่างยิ่งการอ่านส่วนประกอบและกลไกการเขียนเป็นของหายาก .
2. การอ่านและการเขียนวัตถุ (filer) และกลไกการอ่านและการเขียนส่วนประกอบ
วัตถุ Filer ส่วนใหญ่จะใช้เพื่อเข้าถึงไฟล์และส่วนประกอบของ Delphi ในไฟล์แบบฟอร์ม
ไฟล์ DFM ใช้สำหรับแบบฟอร์มการจัดเก็บ Delphi รูปแบบเป็นแกนหลักของการเขียนโปรแกรมภาพ Delphi แบบฟอร์มสอดคล้องกับหน้าต่างในแอปพลิเคชัน Delphi ส่วนประกอบที่มองเห็นในรูปแบบสอดคล้องกับองค์ประกอบอินเตอร์เฟสในหน้าต่างและส่วนประกอบที่ไม่ใช่ภาพเช่น TTimer และ topendialog ซึ่งสอดคล้องกับฟังก์ชั่นบางอย่างของแอปพลิเคชัน Delphi การออกแบบแอปพลิเคชัน Delphi นั้นเน้นการออกแบบแบบฟอร์ม ดังนั้นไฟล์ DFM จึงดำรงตำแหน่งที่สำคัญมากในการออกแบบแอปพลิเคชัน Delphi องค์ประกอบทั้งหมดในแบบฟอร์มรวมถึงคุณสมบัติของแบบฟอร์มจะรวมอยู่ในไฟล์ DFM
ในหน้าต่างแอปพลิเคชัน Delphi องค์ประกอบอินเทอร์เฟซเชื่อมต่อกันโดยความสัมพันธ์ความเป็นเจ้าของดังนั้นโครงสร้างของต้นไม้จึงเป็นการแสดงออกที่เป็นธรรมชาติที่สุด ไฟล์ DFM ถูกเก็บไว้ในข้อความ (เก็บไว้ก่อนหน้านี้เป็นไฟล์ไบนารีใน Delphi2.0) และอย่างมีเหตุผลพวกเขาจัดเรียงความสัมพันธ์ของแต่ละองค์ประกอบในโครงสร้างต้นไม้ จากข้อความนี้คุณสามารถเห็นโครงสร้างต้นไม้ของแบบฟอร์ม นี่คือเนื้อหาของไฟล์ DFM:
Object Form1: tform1
ซ้าย = 197
ด้านบน = 124
-
Pixelsperinch = 96
textheight = 13
ปุ่มปุ่ม 1: tbutton
ซ้าย = 272
-
คำบรรยายภาพ = 'button1'
taborder = 0
จบ
แผงวัตถุ 1: tpanel
ซ้าย = 120
-
คำบรรยายภาพ = 'Panel1'
taborder = 1
ช่องทำเครื่องหมายวัตถุ 1: tcheckbox
ซ้าย = 104
-
คำบรรยายภาพ = 'ช่องทำเครื่องหมาย 1'
taborder = 0
จบ
จบ
จบ
ไฟล์ DFM นี้ถูกสร้างขึ้นโดย TWRITER ผ่านสตรีมวัตถุสตรีมมิ่ง .
เมื่อโปรแกรมเริ่มทำงาน Treader จะอ่านแบบฟอร์มและส่วนประกอบผ่านสตรีมวัตถุสตรีมเนื่องจากเมื่อ Delphi รวบรวมโปรแกรมจะใช้คำสั่งรวบรวม {$ r *.dfm} เพื่อรวบรวมข้อมูลไฟล์ DFM ลงในไฟล์ที่ดำเนินการโดยใช้การรวบรวม คำสั่ง {$ r *.dfm}
Treader และ Twriter ไม่เพียง แต่สามารถอ่านและเขียนประเภทข้อมูลมาตรฐานส่วนใหญ่ในวัตถุ Pascal แต่ยังอ่านและเขียนประเภทขั้นสูงเช่นรายการและตัวแปรและแม้แต่อ่านและเขียน perperties และส่วนประกอบ อย่างไรก็ตาม Treader และ Twriter นั้นมีฟังก์ชั่นที่ จำกัด มากและงานจริงส่วนใหญ่ทำโดย TStream ซึ่งเป็นคลาสที่ทรงพลังมาก กล่าวอีกนัยหนึ่ง Treader และ Twriter เป็นเพียงเครื่องมือซึ่งรับผิดชอบเฉพาะวิธีการอ่านและเขียนส่วนประกอบ
เนื่องจาก Tfiler เป็นชนชั้นบรรพบุรุษของ Treader และ Twriter เพื่อทำความเข้าใจกับ Treader และ Twriter เริ่มต้นด้วย Tfiler
ผู้ส่ง
ก่อนอื่นให้ดูที่คำจำกัดความของคลาส tfiler:
tfiler = คลาส (tobject)
ส่วนตัว
fstream: tstream;
Fbuffer: ตัวชี้;
fbufsize: จำนวนเต็ม;
FBUFPOS: จำนวนเต็ม;
fbufend: จำนวนเต็ม;
FROOT: TCOMPONENT;
Flookuproot: TComponent;
fancestor: tpersistent;
Fignorechildren: บูลีน;
ได้รับการคุ้มครอง
SetRoot ขั้นตอน (ค่า: TComponent);
สาธารณะ
ตัวสร้างสร้าง (สตรีม: tstream; bufsize: จำนวนเต็ม);
Destructor ทำลาย;
ขั้นตอนการกำหนดการจัดหา (ชื่อ Const: String;
Readdata: TreaderProc;
Hasdata: บูลีน);
ขั้นตอน defineBinaryProperty (ชื่อ const: String;
Readdata, WriteData: TStreamProc;
Hasdata: บูลีน);
ขั้นตอน Flushbuffer;
รูทคุณสมบัติ: tComponent อ่าน froot เขียน setroot;
สถานที่ให้บริการ lookuproot: tComponent อ่าน flookuproot;
บรรพบุรุษของทรัพย์สิน: tpersistent อ่าน fancestor เขียน fancestor;
Property Congloyechildren: บูลีนอ่าน fignorechildren เขียน fignorechildren;
จบ;
วัตถุ tfiler เป็นคลาสนามธรรมของ treader และ twriter ซึ่งกำหนดคุณสมบัติและวิธีการพื้นฐานที่ใช้สำหรับการจัดเก็บส่วนประกอบ มันกำหนดคุณลักษณะรูท ทำโดยวัตถุสตรีม ดังนั้นตราบใดที่สื่อที่สามารถเข้าถึงวัตถุสตรีมได้ส่วนประกอบสามารถเข้าถึงได้โดยวัตถุ Filer
วัตถุ TFILER ยังมีวิธีการสาธารณะสองวิธีที่กำหนดคุณสมบัติ: DEFINEPROPERTY และ DEFINENCIANTERPROPERTY ซึ่งเปิดใช้งานวัตถุในการอ่านและเขียนคุณสมบัติที่ไม่ได้กำหนดไว้ในส่วนที่เผยแพร่ของส่วนประกอบ มามุ่งเน้นไปที่สองวิธีด้านล่าง
วิธีการ defelEproperty () ใช้เพื่อคงไว้ซึ่งชนิดข้อมูลมาตรฐานเช่นสตริงจำนวนเต็มบูลีนอักขระจุดลอยตัวและ enums
ในวิธีการแน่นอน พารามิเตอร์ชื่อระบุชื่อของแอตทริบิวต์ที่ควรเขียนไปยังไฟล์ DFM ซึ่งไม่ได้กำหนดไว้ในส่วนที่เผยแพร่ของคลาส
พารามิเตอร์ ReadData และ Writedata ระบุวิธีการอ่านและเขียนข้อมูลที่ต้องการเมื่อเข้าถึงวัตถุ ประเภทของพารามิเตอร์ ReadData และพารามิเตอร์ WRITEDATA คือ TreaderProc และ TWRITERPROC ตามลำดับ ทั้งสองประเภทนี้ได้รับการประกาศเช่นนี้:
treaderProc = ขั้นตอน (ผู้อ่าน: treader) ของวัตถุ;
twriterProc = ขั้นตอน (ผู้เขียน: twriter) ของวัตถุ;
พารามิเตอร์ HASDATA กำหนดว่าคุณสมบัติมีข้อมูลที่จะเก็บไว้ที่รันไทม์หรือไม่
วิธีการ definebinaryProperty มีความคล้ายคลึงกันมากมายกับ DefinEproperty
มาอธิบายการใช้วิธีสองวิธีด้านล่าง
เราใส่ส่วนประกอบที่ไม่ใช่ภาพเช่น TTimer ในแบบฟอร์ม ?
เปิดไฟล์ DFM ของแบบฟอร์มนี้และคุณสามารถดูหลายบรรทัดที่คล้ายกับสิ่งต่อไปนี้:
ตัวจับเวลาวัตถุ 1: ttimer
ซ้าย = 184
ด้านบน = 149
จบ
ระบบสตรีมมิ่งของ Delphi สามารถบันทึกข้อมูลที่เผยแพร่เท่านั้น แต่ TTimer ไม่ได้เผยแพร่แอตทริบิวต์ด้านซ้ายและด้านบนดังนั้นข้อมูลเหล่านี้จะถูกบันทึกอย่างไร
TTimer เป็นคลาสที่ได้รับของ TCOMPONENT
ขั้นตอน tComponent.defineProperties (filer: tfiler);
วาจา
บรรพบุรุษ: TComponent;
ข้อมูล: Longint;
เริ่ม
ข้อมูล: = 0;
บรรพบุรุษ: = tComponent (filer.Ancestor);
ถ้าบรรพบุรุษ <> ไม่มีข้อมูล: = Ancestor.fdesigninfo;
filer.defineproperty ('ซ้าย', addlelft, writeleft,
longrec (fdesigninfo) .lo <> longrec (info) .lo);
filer.defineproperty ('top', readtop, writetop,
longrec (fdesigninfo) .hi <> longrec (ข้อมูล) .hi);
จบ;
defineproperties ของ TComponent เป็นวิธีการเสมือนจริงที่เขียนทับคลาสบรรพบุรุษ tpersistent และในคลาส tpersistent วิธีนี้เป็นวิธีการเสมือนจริงที่ว่างเปล่า
ในวิธีการกำหนดเราจะเห็นว่ามีวัตถุฟิลเลอร์เป็นพารามิเตอร์ของมัน ค่า. มันเรียกว่าวิธีการที่แน่นอนของ tfiler และกำหนด readleft, writeleft, readtop, วิธีการ writetop ในการอ่านและเขียนคุณสมบัติด้านซ้ายและด้านบน
ดังนั้นส่วนประกอบใด ๆ ที่ได้มาจาก TComponent แม้ว่าจะไม่มีแอตทริบิวต์ที่เหลือและด้านบนจะมีคุณสมบัติสองคุณสมบัติดังกล่าวเมื่อสตรีมไปยังไฟล์ DFM
ในกระบวนการค้นหาข้อมูลพบว่าข้อมูลไม่กี่ข้อมูลที่เกี่ยวข้องกับกลไกการอ่านและการเขียนส่วนประกอบ เนื่องจากกระบวนการเขียนส่วนประกอบเสร็จสมบูรณ์โดย IDE ของ Delphi ในระหว่างขั้นตอนการออกแบบจึงไม่สามารถติดตามได้สำหรับกระบวนการทำงาน ดังนั้นผู้เขียนจึงเข้าใจกลไกการอ่านขององค์ประกอบโดยการติดตามรหัส VCL ดั้งเดิมในระหว่างการดำเนินการโปรแกรมและวิเคราะห์กลไกการเขียนขององค์ประกอบผ่านกลไกการอ่านและ TWRITER ดังนั้นสิ่งต่อไปนี้จะอธิบายกลไกการอ่านและการเขียนส่วนประกอบตามกระบวนการคิดนี้ก่อนที่จะพูดคุยเกี่ยวกับ treader และจากนั้น twriter
คนเดินเท้า
ก่อนอื่นดูที่ไฟล์โครงการของ Delphi และคุณจะพบรหัสสองสามบรรทัดเช่นนี้:
เริ่ม
Application.initialize;
application.createform (tform1, form1);
Application.run;
จบ.
นี่คือทางเข้าสู่โปรแกรม Delphi เพียงใส่ความหมายของบรรทัดของรหัสเหล่านี้: application.initialize ดำเนินการเริ่มต้นที่จำเป็นในการเริ่มต้นของแอปพลิเคชัน .
สิ่งที่เราใส่ใจมากที่สุดในตอนนี้คือประโยคของการสร้างแบบฟอร์ม รูปแบบและส่วนประกอบในรูปแบบที่สร้างขึ้นอย่างไร? ดังที่ได้กล่าวไว้ก่อนหน้านี้: ส่วนประกอบทั้งหมดในแบบฟอร์มรวมถึงคุณสมบัติของแบบฟอร์มนั้นรวมอยู่ในไฟล์ DFM ลงในไฟล์ที่เรียกใช้งานได้ ดังนั้นจึงสามารถสรุปได้ว่าเมื่อสร้างแบบฟอร์มคุณต้องอ่านข้อมูล DFM
โดยทำตามขั้นตอนโปรแกรมทีละขั้นตอนคุณจะพบว่าโปรแกรมเรียกใช้วิธี readrootComponent ของ treader ในระหว่างการสร้างแบบฟอร์ม จุดประสงค์ของวิธีนี้คือการอ่านส่วนประกอบรูทและส่วนประกอบทั้งหมดที่มี มาดูการใช้วิธีนี้กันเถอะ:
function treader.readrootComponent (root: tComponent): tComponent;
-
เริ่ม
Readsignature;
ผลลัพธ์: = ไม่มี;
globalnamespace.beginwrite;
พยายาม
พยายาม
ReadPrefix (Flags, i);
ถ้า root = nil แล้ว
เริ่ม
ผลลัพธ์: = tComponentClass (findClass (readstr)). สร้าง (ไม่มี);
result.name: = readstr;
จบสิ้น
เริ่ม
ผลลัพธ์: = รูท;
readstr; {ละเว้นชื่อคลาส}
ถ้า csdesigning ในผลลัพธ์ componentState แล้ว
readstr else
เริ่ม
รวม (result.fcomponentState, csloading);
รวม (result.fComponentState, CSReading);
result.name: = finduniquename (readstr);
จบ;
จบ;
froot: = ผลลัพธ์;
ffinder: = tclassfinder.create (tpersistentclass (result.classtype), จริง);
พยายาม
flookuproot: = ผลลัพธ์;
G: = globalloaded;
ถ้า g <> ไม่มี
floaded: = g else
floaded: = tlist.create;
พยายาม
ถ้า floaded.indexof (froot) <0 แล้ว
floaded.add (froot);
fowner: = froot;
รวม (froot.fcomponentState, csloading);
รวม (froot.fcomponentstate, csreading);
froot.readstate (ตัวเอง);
ยกเว้น (froot.fcomponentstate, csreading);
ถ้า g = ไม่มี
สำหรับ i: = 0 ถึง floaded.count - 1 ทำ tComponent (floaded [i]) โหลด;
ในที่สุด
ถ้า g = nil แล้ว floaded.free;
floaded: = nil;
จบ;
ในที่สุด
ffinder.free;
จบ;
-
ในที่สุด
globalnamespace.endwrite;
จบ;
จบ;
readrootComponent การโทรครั้งแรก ReadSignature เพื่ออ่านแท็ก Object Filer ('TPF0') การตรวจจับแท็กก่อนที่จะโหลดวัตถุสามารถป้องกันความประมาทเลินเล่อและการอ่านข้อมูลที่ไม่ได้ผลหรือล้าสมัย
ลองดูที่ ReadPrefix (Flags, I) เมื่อวัตถุเขียนเขียนส่วนประกอบไปยังสตรีมมันมีค่าสองค่าต่อหน้าส่วนประกอบ ค่าที่สองระบุคำสั่งที่สร้างขึ้นในรูปแบบบรรพบุรุษ
จากนั้นหากพารามิเตอร์รูทเป็นไม่มีส่วนประกอบใหม่ที่สร้างขึ้นด้วยชื่อคลาสที่อ่านโดย ReadSt และคุณสมบัติชื่อของส่วนประกอบจะถูกอ่านจากสตรีม; .
froot.readstate (ตัวเอง);
นี่เป็นประโยคที่สำคัญมาก แม้ว่าวิธีการอ่านข้อมูลนี้จะเป็นวิธีการ TComponent แต่การติดตามเพิ่มเติมสามารถพบได้ว่าในที่สุดมันก็อยู่ในที่สุดวิธีการอ่านข้อมูลของ Treader
procedure treader.readdatainner (อินสแตนซ์: tComponent);
วาจา
Oldparent, Oldowner: TComponent;
เริ่ม
ในขณะที่ไม่ได้ endoflist do readproperty (อินสแตนซ์);
readlistend;
oldparent: = ผู้ปกครอง;
Oldowner: = เจ้าของ;
ผู้ปกครอง: = instance.getChildParent;
พยายาม
เจ้าของ: = instance.getChildowner;
หากไม่ได้รับมอบหมาย (เจ้าของ) จากนั้นเจ้าของ: = รูท;
ในขณะที่ไม่ใช่ endoflist do readComponent (ไม่มี);
readlistend;
ในที่สุด
ผู้ปกครอง: = oldparent;
เจ้าของ: = Oldowner;
จบ;
จบ;
มีรหัสบรรทัดนี้:
ในขณะที่ไม่ได้ endoflist do readproperty (อินสแตนซ์);
สิ่งนี้ใช้ในการอ่านคุณสมบัติของส่วนประกอบรูท สำหรับคุณสมบัติที่แตกต่างกันทั้งสองนี้ควรมีวิธีการอ่านที่แตกต่างกันสองวิธี
Procedure Treader.ReadProperty (AINSTANCE: TPERSISTENT);
-
เริ่ม
-
propinfo: = getpropinfo (instance.classinfo, fpropname);
ถ้า propinfo <> nil แล้ว readpropValue (อินสแตนซ์, propinfo) อื่น ๆ
เริ่ม
{ไม่สามารถกู้คืนได้อย่างน่าเชื่อถือจากข้อผิดพลาดในคุณสมบัติที่กำหนด}
fcanhandleexcepts: = false;
Instance.defineProperties (ตัวเอง);
fcanhandleexcepts: = true;
ถ้า fpropname <> '' แล้ว
PropertyError (fpropname);
จบ;
-
จบ;
เพื่อประหยัดพื้นที่มีการละเว้นรหัสบางอย่าง
propinfo: = getpropinfo (instance.classinfo, fpropname);
รหัสนี้จะได้รับข้อมูลของคุณสมบัติ fpropname ที่เผยแพร่ จากรหัสต่อไปนี้เราจะเห็นได้ว่าหากข้อมูลแอตทริบิวต์ไม่ว่างเปล่าค่าแอตทริบิวต์จะถูกอ่านผ่านวิธีการอ่านค่าและวิธีการอ่านค่าอ่านค่าแอตทริบิวต์ผ่านฟังก์ชัน RTTI ซึ่งจะไม่ถูกนำเสนอในรายละเอียดที่นี่ หากข้อมูลแอตทริบิวต์ว่างเปล่าหมายความว่าแอตทริบิวต์ fpropname ไม่ได้เผยแพร่และจะต้องอ่านผ่านกลไกอื่น นี่คือวิธีการ defineproperties ที่กล่าวถึงข้างต้นดังนี้:
Instance.defineProperties (ตัวเอง);
วิธีนี้เรียกวิธีการ defeleproperty ของ treader:
Procedure Treader.defineProperty (ชื่อ const: String;
Readdata: TreaderProc;
เริ่ม
ถ้า sametext (ชื่อ fpropname) และกำหนด (readdata) แล้ว
เริ่ม
Readdata (ตัวเอง);
fpropname: = '';
จบ;
จบ;
ก่อนที่จะเปรียบเทียบว่าชื่อแอตทริบิวต์การอ่านเหมือนกับชื่อแอตทริบิวต์ที่ตั้งไว้ล่วงหน้าหรือไม่
ตกลงส่วนประกอบรูทได้รับการอ่านและขั้นตอนต่อไปควรอ่านส่วนประกอบที่เป็นเจ้าของโดยส่วนประกอบรูท มาดูวิธีการอีกครั้ง:
procedure treader.readdatainner (อินสแตนซ์: tComponent);
มีรหัสตามวิธีนี้:
ในขณะที่ไม่ใช่ endoflist do readComponent (ไม่มี);
นี่คือสิ่งที่ใช้ในการอ่านส่วนประกอบเด็ก กลไกการอ่านของส่วนประกอบเด็กนั้นเหมือนกับการอ่านส่วนประกอบรากที่แนะนำข้างต้นซึ่งเป็นการสำรวจลึกของต้นไม้
จนถึงตอนนี้กลไกการอ่านส่วนประกอบได้รับการแนะนำ
มาดูกลไกการเขียนส่วนประกอบ เมื่อเราเพิ่มส่วนประกอบลงในแบบฟอร์มคุณสมบัติที่เกี่ยวข้องจะถูกบันทึกไว้ในไฟล์ DFM และกระบวนการนี้จะทำโดย TWRITER
Ø Twriter
วัตถุ Twriter เป็นวัตถุตัวกรองที่สามารถเขียนข้อมูลลงในสตรีมได้ วัตถุ TwRiter ได้รับการสืบทอดโดยตรงจาก TFILER
วัตถุ Twriter มีวิธีการหลายวิธีในการเขียนข้อมูลประเภทต่าง ๆ ลงในสตรีม ดังนั้นในการควบคุมการใช้งานและวิธีการของแอปพลิเคชันของวัตถุ TwRiter คุณต้องเข้าใจรูปแบบของวัตถุนักเขียนที่จัดเก็บข้อมูล
สิ่งแรกที่ควรทราบคือการสตรีม Object Filer แต่ละรายการมีแท็กวัตถุ Filer แท็กนี้ใช้เวลาสี่ไบต์และค่าของมันคือ "tpf0" วัตถุ Filer เข้าถึงแท็กสำหรับวิธีการเขียนและการจัดอ่าน แท็กนี้ส่วนใหญ่จะใช้เพื่อเป็นแนวทางในการดำเนินการอ่านเมื่อวัตถุอ่านข้อมูลอ่านข้อมูล (ส่วนประกอบ ฯลฯ )
ประการที่สองวัตถุผู้เขียนจะต้องทิ้งบิตธงไบต์ไว้ก่อนที่จะจัดเก็บข้อมูลเพื่อระบุประเภทของข้อมูลที่เก็บไว้ในภายหลัง ไบต์นี้เป็นค่าของประเภท tvaluetype Tvaluetype เป็นประเภท enum ที่ใช้พื้นที่หนึ่งไบต์และคำจำกัดความของมันมีดังนี้:
tvaluetype = (vanull, valist, vaint8, vaint16, vaint32, vaentended, vastring, vaident,
Vafalse, Vatrue, Vabinary, Vaset, Valstring, Vanil, Vacollection);
ดังนั้นในการใช้วิธีการเขียนข้อมูลแต่ละรายการของวัตถุนักเขียนคุณต้องเขียนบิตธงก่อนจากนั้นเขียนข้อมูลที่เกี่ยวข้อง การอ่านข้อมูล โลโก้ Valist มีวัตถุประสงค์พิเศษ ดังนั้นเมื่อเขียนรายการที่เหมือนกันหลายรายการในวัตถุนักเขียนให้ใช้ WriteListbegin ก่อนเพื่อเขียนธง Valist และหลังจากเขียนรายการข้อมูลแล้วเขียนธง Vanull ใช้ฟังก์ชั่น endoflist ตรงกลางตรวจสอบว่ามีธง vanull หรือไม่
ลองมาดูวิธีที่สำคัญมากสำหรับ Twriter WriteTata:
โพรซีเดอร์ twriter.writedata (อินสแตนซ์: tComponent);
-
เริ่ม
-
writeprefix (ธง, fchildpos);
ถ้า usequalifiedNames แล้ว
writestr (gettypedata (ptypeinfo (instance.classtype.classinfo)). unitname + '.' + instance.classname)
อื่น
writestr (instance.classname);
writestr (instance.name);
Propertiesposition: = ตำแหน่ง;
if (FancestorList <> nil) และ (fancestorpos <fancestorlist.count) จากนั้น
เริ่ม
ถ้าบรรพบุรุษ <> ไม่มี Inc (FancestorPos);
Inc (fchildpos);
จบ;
writeproperties (อินสแตนซ์);
Writelistend;
-
จบ;
จากวิธี Writedata เราสามารถเห็นภาพทั่วไปของการสร้างข้อมูลไฟล์ DFM ก่อนอื่นเขียนธง (คำนำหน้า) ด้านหน้าของส่วนประกอบจากนั้นเขียนชื่อคลาสและชื่ออินสแตนซ์ จากนั้นมีประโยคเช่นนี้:
writeproperties (อินสแตนซ์);
สิ่งนี้ใช้ในการเขียนคุณสมบัติของส่วนประกอบ ดังที่ได้กล่าวไว้ก่อนหน้านี้ในไฟล์ DFM มีทั้งแอตทริบิวต์ที่เผยแพร่และคุณลักษณะที่ไม่ได้เผยแพร่ ลองมาดูการใช้งาน writeproperties:
ขั้นตอน twriter.writeproperties (อินสแตนซ์: tpersistent);
-
เริ่ม
นับ: = getTypedata (instance.classinfo)^. propcount;
ถ้านับ> 0 แล้ว
เริ่ม
getMem (proplist, count * sizeof (ตัวชี้));
พยายาม
getPropinfos (instance.classinfo, prolist);
สำหรับ i: = 0 ถึงนับ - 1 ทำ
เริ่ม
propinfo: = proplist^[i];
ถ้า propinfo = nil แล้ว
หยุดพัก;
ถ้า isstoredprop (อินสแตนซ์ propinfo) แล้ว
writeproperty (อินสแตนซ์, propinfo);
จบ;
ในที่สุด
Freemem (proplist, count * sizeof (ตัวชี้));
จบ;
จบ;
Instance.defineProperties (ตัวเอง);
จบ;
โปรดดูรหัสต่อไปนี้:
ถ้า isstoredprop (อินสแตนซ์ propinfo) แล้ว
writeproperty (อินสแตนซ์, propinfo);
ฟังก์ชั่น ISSTORDPROP กำหนดว่าจะต้องมีการบันทึกคุณสมบัติหรือไม่โดยการจัดเก็บรอบคัดเลือก
หลังจากบันทึกคุณสมบัติที่เผยแพร่แล้วคุณสมบัติที่ไม่ได้เผยแพร่จะต้องได้รับการบันทึก
Instance.defineProperties (ตัวเอง);
การดำเนินการของ DefinEproperties ได้รับการกล่าวถึงก่อนหน้านี้
ตกลงจนถึงตอนนี้ยังมีคำถาม: ส่วนประกอบของเด็กที่เป็นเจ้าของโดยส่วนประกอบรูทจะถูกบันทึกไว้อย่างไร? มาดูวิธี Writedata (วิธีนี้ถูกกล่าวถึงก่อนหน้านี้):
โพรซีเดอร์ twriter.writedata (อินสแตนซ์: tComponent);
-
เริ่ม
-
ถ้าไม่ไม่รู้
พยายาม
ถ้า (Fancestor <> nil) และ (fancestor เป็น tComponent) แล้ว
เริ่ม
if (fancestor เป็น tComponent) และ (csinline ใน tComponent (fancestor) .ComponentState) แล้ว
frootancestor: = tComponent (fancestor);
FancestorList: = tlist.create;
tComponent (fancestor). getChildren (addancestor, frootancestor);
จบ;
ถ้า csInline ในอินสแตนซ์ ComponentState แล้ว
froot: = อินสแตนซ์;
instance.getChildren (writeComponent, froot);
ในที่สุด
Fancestorlist.free;
จบ;
จบ;
ทรัพย์สินของคนโง่เขลาช่วยให้วัตถุนักเขียนสามารถจัดเก็บส่วนประกอบได้โดยไม่ต้องเก็บส่วนประกอบเด็กที่เป็นเจ้าของโดยส่วนประกอบ หากทรัพย์สินของคนโง่เขลาเป็นจริงวัตถุนักเขียนจะไม่เก็บส่วนประกอบเด็กที่มีเมื่อเก็บส่วนประกอบ มิฉะนั้นจะมีการจัดเก็บส่วนประกอบย่อย
instance.getChildren (writeComponent, froot);
นี่เป็นประโยคที่สำคัญที่สุดสำหรับการเขียนส่วนประกอบย่อย ด้วยวิธีนี้สิ่งที่เราเห็นในไฟล์ DFM เป็นโครงสร้างส่วนประกอบที่เหมือนต้นไม้