Delphi의 구성 요소 읽기 및 쓰기 메커니즘 (I)
1. 스트리밍 객체 (스트림) 및 읽기 쓰기 개체 (파일러) 소개
객체 지향 프로그래밍에서 객체 기반 데이터 관리는 매우 중요한 위치를 차지합니다. Delphi에서 객체 기반 데이터 관리의 지원 방법은 주요 기능 중 하나입니다.
Delphi는 객체 지향적 인 시각적 디자인과 객체 지향 언어를 결합한 통합 개발 환경입니다. 델파이의 핵심은 구성 요소입니다. 구성 요소는 객체의 한 유형입니다. 델파이 애플리케이션은 전적으로 구성 요소에 의해 구성되므로 고성능 델파이 애플리케이션을 개발하는 데 필연적으로 객체 기반 데이터 관리 기술이 포함됩니다.
객체 기반 데이터 관리에는 두 가지 측면이 포함됩니다.
● 객체를 사용하여 데이터를 관리합니다
● 다양한 데이터 개체 관리 (개체 및 구성 요소 포함)
Delphi는 객체 기반 데이터 관리 클래스를 객체 (스트림) 및 Filer Objects (Filer)로 스트리밍하고 VCL (Visual Component Class 라이브러리)의 모든 측면에 적용합니다. 메모리, 외부 메모리 및 Windows 리소스에서 객체를 관리하는 풍부한 기능을 제공합니다.
스트리밍 객체라고도하는 스트림 객체는 tstream, thandlestream, tfilestream, tmemorystream, tresourcestream 및 tblobstream의 일반적인 용어입니다. 다양한 미디어에 데이터를 저장하고 메모리, 메모리 외 및 데이터베이스 필드에서 다양한 데이터 유형 (객체 및 구성 요소 포함)의 관리 작업을 객체 방법으로 사용하는 기능을 나타냅니다. 이 중 응용 프로그램은 다양한 스트림 객체의 데이터를 상당히 쉽게 복사 할 수 있습니다.
객체를 읽고 쓰기 (파일러)에는 tfiler 객체, 트레이더 객체 및 Twriter 객체가 포함됩니다. tfiler 객체는 파일 읽기 및 쓰기의 기본 객체이며 응용 프로그램에서 트레이더 및 Twriter의 주요 용도입니다. 트레이더와 Twriter 객체는 모두 tfiler 객체에서 직접 상속됩니다. tfiler 객체는 파일러 객체의 기본 특성과 방법을 정의합니다.
Filer Object는 주로 두 가지 주요 기능을 수행합니다.
● 양식 파일의 파일 및 구성 요소에 액세스하십시오
● 데이터 읽기 속도를 높이기위한 데이터 버퍼링 제공 및 작업 작업 속도
스트리밍 객체에 대한 지각 적 이해를하고 객체를 읽고 쓰기 위해 먼저 예를 살펴 보겠습니다.
a) 파일을 작성하십시오
절차 tfomr1.writedata (발신자 : tobject);
var
FILESTREAM : tfilestream;
MyWriter : Twriter;
I : 정수
시작하다
filestream : = tfilestream.create ( 'c : /test.txt',fmopenwrite); // 파일 스트림 객체를 만듭니다
mywriter : = twriter.create (Filestream, 1024);
mywriter.writeListBegin; // 쓰기 시작 플래그
i : = 0 to memo1.lines.count-1 do
mywriter.writestring (memo1.lines [i]); // 메모 구성 요소에서 파일에 텍스트 정보를 저장합니다
mywriter.writeListend;
filestream.seek (0, sofrombeginning); // 스트림 시작 위치로 이동합니다.
mywriter.free; // release mywriter 객체
filestream.free; // 릴리스 Filestream 객체
끝;
b) 파일을 읽으십시오
절차 tform1.ReadData (sender : tobject);
var
FILESTREAM : tfilestream;
MyReader : Treader;
시작하다
filestream : = tfilestream.create ( 'c : /test.txt',fmopenread);
myReader : = trreader.create (Filestream, 1024);
myReader.readListBegin; // 작성 목록 시작 플래그
memo1.lines.clear; // memo1 구성 요소의 텍스트 내용을 지 웁니다
myReader.endofList는 아니지만 treader의 메소드 : endoflist를 참고하십시오
시작하다
memo1.lines.add (myReader.ReadString); // 문자열을 memo1 구성 요소에 추가합니다
끝;
myReader.readListend; // 서면 목록의 끝 깃발을 읽으십시오
myReader.free; // release myReader 객체
filestream.free; // 릴리스 Filestream 객체
끝;
위의 두 프로세스는 작문 과정을위한 것이고 다른 프로세스는 읽기 과정을위한 것입니다. 쓰기 프로세스는 Twriter를 사용하여 TFILESTREAM을 사용하여 디스크에 저장된 이진 파일로 내용 (텍스트 정보)을 메모에 저장합니다. 읽기 과정은 트레드더를 통해 쓰기 과정과 반대입니다. Tfilestream은 이진 파일의 내용을 텍스트 정보로 변환하여 메모에 표시합니다. 프로그램을 실행하면 읽기 과정이 작문 과정에서 저장된 정보를 충실하게 복원한다는 것을 알 수 있습니다.
다음 그림은 데이터 객체 (객체 및 구성 요소 포함), 스트리밍 객체 및 객체를 읽고 쓰는 것의 관계를 설명합니다.
그림 (1)
tfiler 객체, 트레이더 객체 및 Twriter 객체와 같은 객체를 읽고 쓰는 것은 일반적으로 구성 요소의 상태를 읽고 쓰는 데 거의 사용되지 않습니다. 구성 요소 메커니즘을 작성하십시오.
스트리밍 객체 스트림의 경우 많은 참조 자료가 상세하게 도입되는 반면 TFiler 객체, 트레이더 객체 및 Twriter 객체에 대한 참조 자료, 특히 구성 요소 읽기 및 쓰기 메커니즘은 구성 요소 판독 및 쓰기 메커니즘의 원래 VCL 코드 분석을 추적합니다. .
2. 개체 읽기 및 쓰기 (Filer) 및 구성 요소 읽기 및 쓰기 메커니즘
Filer 객체는 주로 Filer 객체를 명확하게 이해하기 위해 Delphi Form 파일 (DFM 파일)의 구조에 대해 명확하게 이해해야합니다.
DFM 파일은 델파이 스토리지 양식에 사용됩니다. 양식은 델파이 비주얼 프로그래밍의 핵심입니다. 이 양식은 델파이 응용 프로그램의 창에 해당하며, 형식의 시각적 구성 요소는 윈도우의 인터페이스 요소에 해당하며, 델파이 응용 프로그램의 특정 함수에 해당하는 TTIMER 및 TOPENDIALOG와 같은 비 시각적 구성 요소에 해당합니다. 델파이 응용 프로그램의 설계는 실제로 양식의 설계에 중점을 둡니다. 따라서 DFM 파일은 Delphi Application Design에서 매우 중요한 위치를 차지합니다. 양식의 자체 속성을 포함한 양식의 모든 요소는 DFM 파일에 포함됩니다.
델파이 응용 프로그램 창에서, 인터페이스 요소는 소유권 관계에 의해 상호 연결되어 있으므로 트리 구조는 가장 자연스러운 표현입니다. DFM 파일은 물리적으로 텍스트 (이전에 Delphi2.0의 이진 파일로 저장)에 저장되며 논리적으로는 각 구성 요소의 트리 구조에 관계를 정렬합니다. 이 텍스트에서 양식의 트리 구조를 볼 수 있습니다. DFM 파일의 내용은 다음과 같습니다.
객체 form1 : tform1
왼쪽 = 197
상단 = 124
...
PixelsperInch = 96
Textheight = 13
객체 버튼 1 : tbutton
왼쪽 = 272
...
캡션 = 'button1'
taborder = 0
끝
객체 패널 1 : tpanel
왼쪽 = 120
...
캡션 = '패널1'
taborder = 1
Object CheckBox1 : tcheckbox
왼쪽 = 104
...
캡션 = 'checkbox1'
taborder = 0
끝
끝
끝
이 DFM 파일은 물론 Twriter에 의해 생성되며, 바이너리 파일에서 텍스트 정보 파일로의 변환 프로세스는이 기사에서 연구 할 객체가 아닙니다. .
프로그램이 실행되기 시작하면 Treader는 스트림 객체 스트림을 통해 양식 및 구성 요소를 읽습니다. Delphi가 프로그램을 컴파일 할 때 컴파일 명령어 {$ r *.dfm}을 사용하여 컴파일을 사용하여 DFM 파일 정보를 실행 가능한 파일로 컴파일하기 때문입니다. 명령어 {$ r *.dfm}.
Treader와 Twriter는 Object Pascal에서 대부분의 표준 데이터 유형을 읽고 쓸 수있을뿐만 아니라 목록 및 변형과 같은 고급 유형을 읽고 쓸 수 있으며, 심지어 Perperties 및 구성 요소를 읽고 씁니다. 그러나 Treader와 Twriter 자체는 실제로 매우 제한된 기능을 제공하며 실제 작업의 대부분은 매우 강력한 클래스 인 TStream에 의해 수행됩니다. 다시 말해, Treader와 Twriter는 실제로 도구 일뿐입니다.이 도구는 특정 읽기 및 쓰기 작업에 대해서는 구성 요소를 읽고 쓰는 방법에만 책임이 있습니다.
Tfiler는 Treader와 Twriter의 공개 조상 클래스이므로 Treader와 Twriter를 이해하기 위해 Tfiler로 시작하십시오.
tfiler
먼저 tfiler 클래스의 정의를 살펴 보겠습니다.
tfiler = class (tobject)
사적인
fstream : tstream;
fbuffer : 포인터;
fbufsize : 정수;
fbufpos : 정수;
fbufend : 정수;
Froot : tcomponent;
flookuproot : tcomponent;
팬스 테이터 : tpersistent;
Fignorechildren : 부울;
보호
절차 setRoot (value : tcomponent);
공공의
생성자 생성 (스트림 : tstream; bufsize : Integer);
소멸자 파괴;
프로 시저 DefineProperty (const 이름 : 문자열;
ReadData : TreaderProc;
Hasdata : 부울;
절차 DefineBinalProperty (const 이름 : String;
readData, writedata : tstreamProc;
Hasdata : 부울;
절차 플러시 버퍼;
속성 루트 : tcomponent 읽기 froot write setRoot;
속성 LookUproot : tcomponent Read Flookuproot;
속성 조상 : Tpersistent Read Fancestor Write Fancestor;
재산 무시 : 부울 읽기 Fignorechildren 쓰기 Fignorechildren;
끝;
tfiler 객체는 추상적 인 클래스의 트레이더 및 Twriter 클래스로 구성 요소 저장에 사용되는 기본 특성 및 메소드를 정의합니다. 루트 속성을 정의합니다. 루트는 읽기 또는 작성된 메소드의 루트 객체를 지정합니다. 스트림 객체로 만든. 따라서 스트림 객체에 액세스 할 수있는 미디어가 파일러 객체에 의해 구성 요소에 액세스 할 수 있습니다.
TFILER 객체는 속성을 정의하는 두 가지 공개 방법을 제공합니다 : DefineProperty 및 DefineBinaryProperty는 객체가 구성 요소의 게시 된 부분에 정의되지 않은 속성을 읽고 쓸 수 있도록합니다. 아래 두 가지 방법에 중점을 두겠습니다.
DefineProperty () 메소드는 문자열, 정수, 부울, 문자, 부동 소수점 및 열거와 같은 표준 데이터 유형을 지속하는 데 사용됩니다.
DefineProperty 메소드에서. 이름 매개 변수는 클래스의 게시 된 부분에 정의되지 않은 DFM 파일에 기록되어야하는 속성의 이름을 지정합니다.
readData 및 writedata 매개 변수는 객체에 액세스 할 때 필요한 데이터를 읽고 쓰는 메소드를 지정합니다. readData 파라미터 및 writedata 매개 변수의 유형은 각각 트레드 르프로 및 TwriterProc입니다. 이 두 유형은 다음과 같이 선언됩니다.
TreaderProc = 객체의 절차 (Reader : Treader);
TwriterProc = 객체의 절차 (Writer : Twriter);
Hasdata 매개 변수는 속성에 런타임에 저장 될 데이터가 있는지 여부를 결정합니다.
DefineBinalProperty 방법은 Sound 및 이미지와 같은 이진 데이터를 저장하는 데 사용됩니다.
아래 두 가지 방법의 사용을 설명해 봅시다.
우리는 양식에 Timer와 같은 비 시각적 구성 요소를 양식에 다시 열었을 때 Ttimer가 여전히 원래 위치에 있음을 발견했지만 TTIMER는 왼쪽 및 상단 속성이 없으므로 위치 정보가 저장되어 있습니다. ?
이 양식의 DFM 파일을 열면 다음과 유사한 여러 줄을 볼 수 있습니다.
Object Timer1 : Ttimer
왼쪽 = 184
상단 = 149
끝
Delphi의 스트리밍 시스템은 게시 된 데이터 만 저장할 수 있지만 Ttimer는 왼쪽 및 최고 속성을 게시하지 않았으므로 이러한 데이터는 어떻게 저장됩니까?
ttimer는 tcomponent 클래스에서 파생 된 클래스입니다.
절차 tcomponent.defineProperties (filer : tfiler);
var
조상 : tcomponent;
정보 : Longint;
시작하다
정보 : = 0;
조상 : = tcomponent (filer.ancestor);
조상 <> nil이면 정보 : = 조상 .fdesigninfo;
filer.defineProperty ( '왼쪽', Readleft, Writeleft,
longrec (fdesigninfo) .lo <> longrec (info) .lo);
filer.defineProperty ( 'TOP', ReadTop, WriteTop,
longrec (fdesigninfo) .hi <> longrec (info) .hi);
끝;
tcomponent의 defineproperties는 조상 클래스 tpersistent를 덮어 쓰는 가상 메소드이며, tpersistent 클래스 에서이 방법은 빈 가상 메소드입니다.
DefineProperties 방법에서는 속성을 정의 할 때 파일러 객체가 있음을 알 수 있습니다. 값. 그것은 tfiler의 defineproperty 메소드를 호출하고 readleft, writeLeft, readtop, left and operties를 읽고 쓸 수있는 readleft, writeleft, readtop, writeTop 방법을 정의합니다.
따라서, 왼쪽 및 상단 속성이없는 경우에도 TComponent에서 파생 된 모든 구성 요소는 DFM 파일로 스트리밍 할 때 두 가지 속성을 갖습니다.
데이터를 검색하는 과정에서 구성 요소 읽기 및 쓰기 메커니즘과 관련된 데이터는 거의 없습니다. 디자인 단계에서 Delphi의 IDE에 의해 구성 요소 쓰기 프로세스가 완료되므로 실행 프로세스를 위해 추적 할 수 없습니다. 따라서 저자는 프로그램 작동 중 원래 VCL 코드를 추적하여 구성 요소의 읽기 메커니즘을 이해하고 읽기 메커니즘과 Twriter를 통해 구성 요소의 쓰기 메커니즘을 분석합니다. 따라서 다음은이 사고 과정에 따라 구성 요소 읽기 및 쓰기 메커니즘을 설명하고 먼저 Treader에 대해 이야기 한 다음 Twriter를 설명합니다.
트레이더
먼저 Delphi의 프로젝트 파일을 살펴보면 다음과 같은 몇 줄의 코드를 찾을 수 있습니다.
시작하다
application.initialize;
application.createform (tform1, form1);
application.run;
끝.
이것은 델파이 프로그램의 입구입니다. 이 코드 라인의 의미를 간단히 사용하십시오. 응용 프로그램 실행 시작에서 필요한 초기화 작업을 수행하면 필요한 양식을 작성합니다. .
우리가 지금 가장 관심을 갖는 것은 양식을 만드는 문장입니다. 양식에 양식과 구성 요소는 어떻게 생성됩니까? 앞서 언급 한 바와 같이 : 양식 자체의 속성을 포함한 모든 구성 요소는 Delphi가 프로그램을 컴파일하면 DFM 파일 정보를 컴파일하기 위해 DFM 파일에 포함됩니다. 실행 파일로. 따라서 양식을 작성할 때 DFM 정보를 읽어야한다고 결론 지을 수 있습니다.
프로그램을 단계별로 따르면 프로그램이 양식을 작성하는 동안 Treader의 readRootComponent 메소드를 호출한다는 것을 알 수 있습니다. 이 방법의 목적은 루트 구성 요소와 모든 구성 요소를 읽는 것입니다. 이 방법의 구현을 살펴 보겠습니다.
함수 treader.readRootComponent (root : tcomponent) : tcomponent;
...
시작하다
Readsignature;
결과 : = nil;
GlobalNamespace.beginWrite;
노력하다
노력하다
readprefix (플래그, i);
root = nil이면
시작하다
결과 : = tcomponentClass (findClass (readstrs)). 작성 (nil);
result.name : = readstr;
다른 끝
시작하다
결과 : = 루트;
readSt; {무시}
csdesigning in result.componentState에서
gest else
시작하다
포함 (result.fcomponentState, csloading);
포함 (result.fcomponentstate, csreading);
result.name : = findUniqueName (readstr);
끝;
끝;
froot : = 결과;
ffinder : = tclassfinder.create (tpersistentClass (result.classtype), true);
노력하다
flookuproot : = 결과;
G : = Globalloaded;
G <> nil이라면
floaded : = g else
floaded : = tlist.create;
노력하다
floaded.indexof (froot) <0이면
floaded.add (froot);
Fowner : = Froot;
포함 (froot.fcomponentstate, csloading);
포함 (froot.fcomponentstate, csreading);
froot.readstate (self);
제외 (froot.fcomponentState, CSReading);
g = nil이면
i : = 0 to floaded.count -1 tcomponent (floaded [i]).로드;
마지막으로
g = nil이면 floaded.free;
floaded : = nil;
끝;
마지막으로
ffinder.free;
끝;
...
마지막으로
globalnamespace.endwrite;
끝;
끝;
readRootComponent는 먼저 readSignature를 호출하여 Filer Object Tag ( 'TPF0')를 읽습니다. 객체를로드하기 전에 태그를 감지하면 태만과 비효율적이거나 오래된 데이터 판독 값을 방지 할 수 있습니다.
readprefix (flags, i)를 살펴 보겠습니다. readprefix 메소드의 함수는 읽기 스트림의 구성 요소 앞에있는 로고 (접두사)를 제외하고는 Readsignature의 함수와 매우 유사합니다. 쓰기 객체는 스트림에 구성 요소를 작성하면 구성 요소 앞에서 두 값이 조상 형식으로부터 상속되는 형태와 그 형태의 값을 나타냅니다 두 번째 값은 조상 형식으로 작성된 순서를 나타냅니다.
그런 다음 루트 매개 변수가 nil이면 Readstr에 의해 클래스 이름을 읽고 새 구성 요소가 생성되고 구성 요소의 이름 속성은 스트림에서 읽히고 클래스 이름이 무시됩니다. .
froot.readstate (self);
이것은 매우 중요한 문장입니다. READSTATE 메소드는 루트 구성 요소의 속성과 소유물을 읽습니다. 이 ReadState 방법은 tcomponent 방법이지만, 실제로이 방법의 구현은 다음과 같습니다.
프로 시저 트레이더. ReadDatainner (인스턴스 : tcomponent);
var
Oldparent, Oldowner : tcomponent;
시작하다
endoflist는 readproperty (인스턴스)를 수행하지 않습니다.
리스트리스트;
oldparent : = 부모;
OLDOWNER : = 소유자;
부모 : = instance.getChildParent;
노력하다
소유자 : = instance.getChildowner;
할당되지 않은 경우 (소유자) 소유자 : = root;
endoflist는 readcomponent (nil)를 수행하지 않습니다.
리스트리스트;
마지막으로
부모 : = oldparent;
소유자 : = 노인;
끝;
끝;
이 코드 라인이 있습니다.
endoflist는 readproperty (인스턴스)를 수행하지 않습니다.
이는 앞에서 언급 한 바와 같이 루트 구성 요소의 속성을 읽는 데 사용됩니다. 이 두 가지 속성의 경우이 아이디어를 확인하기 위해서는 두 가지 다른 읽기 방법이 있어야합니다.
프로 시저 트레이더. ReadProperty (ainstance : tpersistent);
...
시작하다
...
propinfo : = getPropinfo (instance.classinfo, fpropname);
propinfo <> nil이면 readpropvalue (indust, propinfo) else
시작하다
{정의 된 속성의 오류에서 안정적으로 복구 할 수 없습니다}
fcanhandleexcepts : = false;
instance.defineProperties (self);
fcanhandleexcepts : = true;
fpropname <> ''라면
PropertionError (fpropname);
끝;
...
끝;
공간을 절약하기 위해 일부 코드가 생략되었습니다. FpropName은 파일에서 읽은 속성입니다.
propinfo : = getPropinfo (instance.classinfo, fpropname);
이 코드는 게시 된 속성 Fpropname의 정보를 얻는 것입니다. 다음 코드에서 속성 정보가 비어 있지 않으면 속성 값이 readPropValue 메소드를 통해 읽히고 readPropValue 메소드가 RTTI 함수를 통해 속성 값을 읽습니다. 여기에는 자세히 도입되지 않습니다. 속성 정보가 비어 있으면 속성 fpropName이 게시되지 않았으며 다른 메커니즘을 통해 읽어야합니다. 이것은 다음과 같이 위에서 언급 한 DefineProperties 방법입니다.
instance.defineProperties (self);
이 방법은 실제로 Treader의 DefineProperty 메소드를 호출합니다.
프로 시저 트레이더 .defineProperty (const 이름 : 문자열;
ReadData : TreaderProc; Hasdata;
시작하다
sametext (이름, fpropname)이고 할당 된 경우 (readData)
시작하다
readData (self);
fpropname : = '';
끝;
끝;
먼저 읽기 속성 이름이 사전 설정 속성 이름과 동일하고 읽기 메소드가 비어 있지 않은지 여부를 비교하십시오.
자, 루트 구성 요소를 읽었으며 다음 단계는 루트 구성 요소가 소유 한 구성 요소를 읽는 것입니다. 메소드를 다시 살펴 보겠습니다.
프로 시저 트레이더. ReadDatainner (인스턴스 : tcomponent);
이 방법에 따른 코드가 있습니다.
endoflist는 readcomponent (nil)를 수행하지 않습니다.
이것은 바로 아동 구성 요소를 읽는 데 사용되는 것입니다. 아동 구성 요소의 읽기 메커니즘은 위에 소개 된 뿌리 성분의 판독과 동일하며, 이는 나무의 깊은 횡선입니다.
지금까지 성분 판독 메커니즘이 도입되었습니다.
구성 요소 쓰기 메커니즘을 살펴 보겠습니다. 구성 요소를 양식에 추가하면 관련 속성이 DFM 파일에 저장 되며이 프로세스는 Twriter에 의해 수행됩니다.
Ø twriter
Twriter Object는 스트림에 데이터를 작성하는 즉각적인 파일러 객체입니다. Twriter 객체는 tfiler에서 직접 상속받는 것 외에도 tfiler에서 상속 된 메소드를 덮어 씁니다. 또한 다양한 데이터 유형 (예 : 정수, 문자열, 구성 요소 등)을 추가합니다.
Twriter 객체는 다양한 유형의 데이터를 스트림에 작성하는 많은 방법을 제공합니다. 따라서 Twriter Objects의 구현 및 응용 방법을 마스터하려면 데이터를 저장하는 Writer Object의 형식을 이해해야합니다.
가장 먼저 주목해야 할 것은 각 파일러 객체 스트림에는 파일러 객체 태그가 포함되어 있다는 것입니다. 이 태그는 4 바이트를 차지하고 그 값은 "TPF0"입니다. Filer Object는 Writesignature 및 Readsignature 메소드의 태그에 액세스합니다. 이 태그는 주로 독자 객체가 데이터 (구성 요소 등)를 읽을 때 읽기 작업을 안내하는 데 사용됩니다.
둘째, Writer Object는 데이터를 저장하기 전에 바이트 플래그를 남겨 두어야합니다. 이 바이트는 TVALUETYPE 유형의 값입니다. TVALUETYPE는 하나의 바이트 공간을 차지하는 열거 유형이며 그 정의는 다음과 같습니다.
TVALUETYPE = (Vanull, Valist, Vaint8, Vaint16, Vaint32, Vaentended, Vastring, Vaident,
Vafalse, Vatrue, Vabinary, Vaset, Valstring, Vanil, vacollection);
따라서 Writer Object의 각 데이터 작성 방법을 구현할 때는 먼저 플래그 비트를 작성한 다음 해당 데이터를 작성해야합니다. 읽기 데이터. 그렇지 않으면 잘못된 읽기 데이터가있는 이벤트가 생성됩니다. Valist 로고는 특별한 목적을 가지고 있습니다. 이는 동일한 유형의 일련의 항목을 식별하는 데 사용되며 연속 항목의 끝을 식별하는 로고는 Vanull입니다. 따라서, 작가 객체에 몇 가지 연속적인 항목을 작성할 때, 먼저 writeListBegin을 사용하여 Valist 플래그를 작성한 다음 Vanull 플래그를 작성 하고이 데이터를 읽을 때 ReadListBegin으로 시작하고 ReadListend로 끝납니다. 중간에 endoflist 함수를 사용하여 Vanull 플래그가 있는지 확인하십시오.
Twriter Writedata의 매우 중요한 방법을 살펴 보겠습니다.
절차 twriter.writedata (인스턴스 : tcomponent);
...
시작하다
...
WritePrefix (플래그, fchildpos);
usequalifiedNames라면
Writest (gettypedata (ptypeinfo (instance.classtype.classinfo)).
또 다른
writest (instance.className);
writest (instance.name);
속성 : = 위치;
if (fancestorlist <> nil) 및 (Fancestorpos <fancestorlist.count)
시작하다
조상 <> nil이면 inc (fancestorpos);
Inc (fchildpos);
끝;
WriteProperties (인스턴스);
WriteListend;
...
끝;
Writedata 메소드에서 DFM 파일 정보를 생성하는 일반적인 그림을 볼 수 있습니다. 먼저 구성 요소 앞에 플래그 (접두사)를 작성한 다음 클래스 이름과 인스턴스 이름을 작성하십시오. 그런 다음 다음과 같은 문장이 있습니다.
WriteProperties (인스턴스);
이것은 구성 요소의 속성을 작성하는 데 사용됩니다. 앞에서 언급했듯이 DFM 파일에는 게시 된 속성과 비 게시 된 속성이 모두 다릅니다. WriteProperties의 구현을 살펴 보겠습니다.
절차 twriter.writeproperties (인스턴스 : tpersistent);
...
시작하다
카운트 : = gettypedata (instance.classinfo)^. propcount;
count> 0이면
시작하다
getMem (proplist, count * sizeof (포인터));
노력하다
getPropinfos (instance.classinfo, proplist);
i : = 0의 경우 - 계산 -1
시작하다
propinfo : = proplist^[i];
propinfo = nil이면
부서지다;
ISSTAREDPROP (indust, propinfo) 인 경우
WriteProperty (인스턴스, propinfo);
끝;
마지막으로
Freemem (proplist, count * sizeof (포인터));
끝;
끝;
instance.defineProperties (self);
끝;
다음 코드를 참조하십시오.
ISSTAREDPROP (indust, propinfo) 인 경우
WriteProperty (인스턴스, propinfo);
이 기능은 예선을 저장 해야하는 경우 부동산을 저장 해야하는지 여부를 결정합니다.
게시 된 속성을 저장 한 후에는 게시되지 않은 속성을 저장해야합니다.
instance.defineProperties (self);
DefineProperties의 구현은 이전에 언급되어 있습니다.
자, 지금까지 여전히 의문이 있습니다. 루트 구성 요소가 소유 한 어린이 구성 요소는 어떻게 저장됩니까? writedata 메소드를 살펴 보겠습니다 (이 방법은 앞에서 언급했습니다) :
절차 twriter.writedata (인스턴스 : tcomponent);
...
시작하다
...
당시 무시하지 않는다면
노력하다
if (fancestor <> nil)과 (Fancestor는 tcomponent)
시작하다
if (fancestor는 tcomponent)이고 (csinline in tcomponent (fancestor) .componentState)
frootancestor : = tcomponent (Fancestor);
Fancestorlist : = tlist.create;
tcomponent (fancestor) .getchildren (Addancestor, frootancestor);
끝;
인스턴스에 csinline 인 경우
Froot : = 인스턴스;
instance.getchildren (writecomponent, froot);
마지막으로
Fancestorlist.free;
끝;
끝;
무시할만한 속성을 통해 작가 객체는 구성 요소가 소유 한 자식 구성 요소를 저장하지 않고 구성 요소를 저장할 수 있습니다. 무시할만한 속성이 참이면, 작가 객체는 구성 요소를 저장할 때 자식 구성 요소를 저장하지 않습니다. 그렇지 않으면 하위 구성 요소가 저장됩니다.
instance.getchildren (writecomponent, froot);
이것은 서브 컴포넌트를 쓰는 가장 중요한 문장입니다. root 구성 요소가 콜백 함수로 사용하고 루트 구성 요소 Froot가 하위 구성 요소를 갖는 경우 writecomponent는 하위 구성 요소를 저장하는 데 사용됩니다. 이런 식으로 DFM 파일에서 볼 수있는 것은 트리와 같은 구성 요소 구조입니다.