Delphi's "Dynamic Form" technology actual application

zhaozj2021-02-16  54

Delphi's "Dynamic Form" technology actual application

Xishan flying fox

2003-4-24

Keywords: Delphi, DFM, Form

For me to ignite less, let's take some information first.

== begin =================================

DFM file and standard text file conversion

In the Delphi visualization design environment, the programmer is allowed to browse and modify the DFM file in the code editor. When using the file / open command to open the DFM file directly or select the View as text command on the pop-up menu of the Form Design window, you will appear in the text form in the editor. In some information, this text is called the form design script. This script editing function provided by Delphi is a major supplement to the Delphi visual design. Of course, this script editing capability is limited, thanks that the part cannot be added and deleted in the script, because the code and the DFM script are closely connected, any addition and modification can cause inconsistencies. But in the dynamically generated DFM file, there is no such limit.

In fact, the DFM file content is binary data, and its script is automatically converted through the Delphi development environment, and the Classes library unit in the Delphi VCL provides file DFM in the binary stream and the mutual transformation of its script. They are ObjectBinaryTotext and ObjectTextTobinary, ObjectResourceTEXT, and ObjectTextToreSource.

The ObjectBinaryTotext process converts the components stored in the binary stream to the text-based expression, so that you can use the text handler to process, you can also use the text editor to find and replace the operation, and finally convert the text to a binary stream. part.

Contrary to the ObjectTextTobinary process, reverse the ObjectBinaryTotext, convert the txt file into a binary stream, and as long as the writing of the TXT file content complies with the DFM script syntax, ObjectTextTobinary converts any program generated TXT file to the part, this function is also The dynamic generation and editing of the DFM file laid the foundation.

How to save this form into a text format during the running process?

Zswang (with water) (2001-11-21 9:52:59) 0 points

Function ComponentTostring (Component: Tcomponent): String;

VAR

Binstream: TMemoryStream;

Strstream: Tstringstream;

String;

Begin

Binstream: = TMEMORYSTREAM.CREATE;

Try

Strstream: = TSTRINGSTREAM.CREATE (S);

Try

Binstream.writeComponent (Component);

Binstream.seek; 0, Sofrombeginning;

ObjectBinaryTotext (Binstream, strstream);

Strstream.seek (0, SOFROMBEGINNIN);

Result: = strstream.datastring;

Finally

STRSTREAM.FREE;

END;

Finally

Binstream.freeend;

End; {companyTostring}

Function stringtocomponent (value: string; instance: tcomponent): tComponent

VAR

Strstream: Tstringstream;

Binstream: TMemoryStream;

Begin

Strstream: = TstringStream.create (Value);

Try

Binstream: = TMEMORYSTREAM.CREATE;

Try

ObjectTextTobinary (Strstream, Binstream);

Binstream.seek; 0, Sofrombeginning;

Result: = binstream.readComponent;

Finally

Binstream.free;

END;

Finally

STRSTREAM.FREE;

END;

End; {StringTOComponent}

Reply to: zswang (Particle water) (2001-11-21 9:54:28) 0 points

Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);

Begin

Memo1.text: = ComponentToString (Self);

END;

Reply to: zswang (with water) (2001-11-21 9:58:13) 0 points

Procedure TFORM1.BUTTON2CLICK (Sender: TOBJECT);

Begin

Stringtocomponent

'Object Label1: TLABEL' # 13 # 10

'Left = 232' # 13 # 10

'TOP = 56' # 13 # 10

'Width = 26' # 13 # 10

'Height = 13' # 13 # 10

'Capen = # 20320 # 22909' # 13 # 10

'Font.charset = GB2312_CHARSET' # 13 # 10

'Font.color = CLRED' # 13 # 10

'Font.height = -13' # 13 # 10

'Font.name = # 23435 # 20307' # 13 # 10

'Font.style = [] # 13 # 10

'ParentFont = false' # 13 # 10

'end' # 13 # 10, label1);

END;

// To register the class

== End =============================================================

Ok, understand the above words, some friends will naturally think that using these functions should be able to get some useful things, I have made a little application, and I have applied it to the project, now I Come to everyone's full description: First, I ask my program to have the following ability:

1. My program's form can be dynamically replaced, do not compile EXE, just replace a DFM form design script (Of course, you can re-encapsulate this DFM file, such as replacing TXT suffixes, etc.).

2. I can preview all DFM files, let it turn into actual FORM views.

Don't underestimate these two points, in many cases, this significance is very significant, raising several examples 1, can complete the interface design and program design, division of labor 2 on-site maintenance, some interface adjustments and function settings You need to find the source code to Delphi to compile it. The old difference to do the MIS class should be able to experience the benefits from this. 3 Some function interface is simple, just let the user download a DFM file to cover the original Yes.

Ok, I don't have any words, the following details how to reach the above two points.

Obviously we have to turn a text into a form, then use this function:

Function stringtocomponent (value: string; instance: tcomponent): tComponent

VAR

Strstream: Tstringstream;

Binstream: TMemoryStream;

Begin

Strstream: = TstringStream.create (Value);

Try

Binstream: = TMEMORYSTREAM.CREATE;

Try

ObjectTextTobinary (Strstream, Binstream);

Binstream.seek; 0, Sofrombeginning;

Result: = binstream.readComponent;

Finally

Binstream.free;

END;

Finally

STRSTREAM.FREE;

END;

END;

However, all CLASS must be registered, for example, the following form1frm.dfm file

Object Form1: TFORM1

LEFT = 222

TOP = 168

Width = 485

HEIGHT = 290

CAPTION = 'FORM1'

Color = CLBTNFACE

Font.charset = default_charset

Font.color = CLWINDOWTEXT

Font.height = -11

Font.name = 'MS SANS Serif'

Font.style = []

OldcreateOrder = FALSE

Pixelsperinch = 96

TEXTHEIGHT = 13

Object Panel1: TPANEL

LEFT = 0

TOP = 0

Width = 477

HEIGHT = 33

Align = altop

Taborder = 0

Object Bitbtn1: Tbitbtn

LEFT = 4

TOP = 4

Width = 75

HEIGHT = 25

CAPTION = 'OK'

Taborder = 0

end

end

Object Memo1: TMEMO

LEFT = 0

TOP = 33

Width = 477

HEIGHT = 230

Align = alclient

Taborder = 1

end

end

You should use this,

Var List: TstringList; Form: TForm

...

List.Lines.LoadFromfile ('form1frm.dfm');

RegisterClass (TFORM1);

RegisterClass (TPANEL);

RegisterClass (TbitBTN);

RegisterClass (TMEMO);

Form: = StringTOComponent (list.lines.text, nil);

Form.showModal ();

...

This will display a form.

However, this has a problem, and the VCL control of Delphi is fixed. It is not a problem with registerclass (...), but TFORM1 is not, if even TFORM1 is registered, you cannot reach the second point requirements. We can change it, because all forms are inherited from TForm, so you should use the registration TForm to replace, so there is a function below:

Function loadTextform (filename: string): tform;

VAR

List: tstrings;

Firstline: String;

IPOS: Integer;

Form: TForm;

Begin

Result: = NIL;

If FileExists (filename) = false then

EXIT;

Form: = tForm.create (Application);

List: = TSTRINGLIST.CREATE;

Try

List.loadfromfile (filename);

if list.count = 0 THEN

EXIT;

Firstline: = List [0];

IPOS: = POS (':', firstline);

If ipos = 0 THEN / / Can't find ':', format is not

EXIT;

List [0]: = Copy (Firstline, 1, IPOS) 'TFORM';

DeleteErrorLines (List);

StringTOComponent (list.text, form);

Result: = form;

Except

Form.free;

Result: = NIL;

END;

List.free;

END;

The principle is to read the category of the form into TFORM after reading the DFM file. There is also a function:

Procedure deleteErrorLines (List: tstrings);

VAR

i: integer;

Line: String;

Begin

if list.count = 0 THEN

EXIT;

I: = 0;

While i

Begin

Line: = trim (List [i]);

IF Copy (Line, 1, 2) = 'on' Then

List.delete (i)

Else

INC (I);

END;

END;

This function deletes any rows that are "on" starting. It should be in Delphi. All controls are beginning to start with "on", deleting such rows, can guarantee StringTOComponent (List.Text, Form); If you don't make a mistake, you can write a DFM form viewer with the above two functions. So far, I haven't found any DFM form viewer. This way we have completed the second request. In practical applications, a form is almost certain will have an event handler, so we have to reach the first request. I have provided two programs here, each has advantages and disadvantages:

Option One:

When the programmer is developed, in the form of formcreate (...), generates a form file with loadTextForm (...), then moves all the controls on the form to this form, and finally find the control on the form, dynamic Set the event handler. This method requires a good set of control naming rules, and the development is more cumbersome, enjoy the Delphi's IDE, the benefits of automatically generate event association code. However, the production staff of the FORM file is small, they can use Delphi to make a form directly.

Option II:

Use this function

Procedure readform (AFILOM: TComponent; AfileName: String = ');

VAR

FRMSTRINGS: TSTRINGS;

Begin

RegisterClass (TPERSISTENTCLASS (AFROM.CLASSTYPE);

FRMSTRINGS: = TSTRINGLIST.CREATE;

Try

if Trim (AfileName) = '' Then frmstrings.loadfromfile (GSPATHINFO '/' AFROM.NAME '. TXT')

Else frMstrings.loadfromfile (afilename);

While Afrom.comPonentcount> 0 do afrom.components [0] .destroy;

AFROM: = StringTOComponent (frMstrings.text, afrom)

Finally

FRMSTRINGS.FREE;

END;

UnregisterClass (TPERSISTENTCLASS (AFROM.CLASSTYPE);

END;

Call Readform (Self, ...) in FormCreate.

This scheme does not limit the limit of the first program, but the developer must first complete a complete Form file to the FORM file producer, the creation of the FORM file cannot modify the NAME of the control, can not add or delete the control, and must be retained Person given all event handlers and cannot modify the function name. However, many problems can write an Form editor to ensure that you can't.

The specific code is not written.

I think there is also a problem with good programs to solve dynamic forms, I hope everyone will discuss.

(The above code is written using Delphi6)

Finally, I give a Unit of a function of the dynamic form in my actual project.

{************************************************

Module No .: J001DFMFUNC

Module Name: DFM Form Function Set Unit

Author:

Liu Aijun

Establishment date: December 2, 2002

Last modified date:

Note: This unit contains some functions for file dynamics based on files in Delphi form file format ************************************* ****************}

UNIT J001DFMFUNC;

Interface

Uses

Windows, Messages, Sysutils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, Extctrls, Dbctrls, Grids, DBGRIDS, Buttons, Stdctrls,

Comctrls, Dbcgrids, ButtonComps, Tabs, QRYGLOBAL

Type

Tallcomponentclass = array of tpersistentclass;

Procedure InitclasStype (ClassArray: TallComponentClass);

Function ComponentTostring (Component: Tcomponent): String;

Function stringtocomponent (value: string; instance: tcomponent): tComponent

Procedure RegisterallClasses (aallcmpclass: tallcomponentclass);

Procedure UnregisterallClasses (aallcmpclass: tallcomponentclass);

Function getObjectString (list: tstrings; begline: integer = 0; typeString: String = ''): string;

Function loadTextform (filename: string): tform;

Function LoadTextform2 (filename: string; out errmsg: string): TForm;

Procedure deleteErrorLines (List: tstrings);

Procedure readform (AFILOM: TComponent; AfileName: String = ');

Const

RegisteredCompoentClassCount = 32; // A number of sets

VAR

AllCMPClass: TallcomponentClass; // Storage control class

IMPLEMentation

// Initialization can be parsed, can increase

Procedure InitclasStype (ClassArray: TallComponentClass);

Begin

SetLength (AllCMPClass, RegisteredCompoentClassCount);

AllCMPClass [0]: = TFORM;

AllCMPClass [1]: = TGROUPBOX;

AllCMPClass [2]: = TPANEL;

AllCMPClass [3]: = TscrollBox;

AllCMPClass [4]: ​​= TLABEL;

AllCMPClass [5]: = tbutton;

AllCMPClass [6]: = Tbitbtn;

AllCMPClass [7]: = tspeedbutton;

AllCMPClass [8]: = TSTRINGGRID;

AllCMPClass [9]: = TIMAGE;

AllCMPClass [10]: = TBevel;

AllCMPClass [11]: = TSTATICTEXT;

AllCMPClass [12]: = TTABCONTROL;

AllCMPClass [13]: = TPAGECONTROL; AllCMPClass [14]: = TTABSHEET

AllCMPClass [15]: = TDBNAVIGATOR;

AllCMPClass [16]: = TDBTEXT;

AllCMPClass [17]: = TDBEDIT;

AllCMPCLASS [18]: = TDBMEMO;

AllCMPClass [19]: = TDBGRID;

AllCMPClass [20]: = TDBCTRLGRID;

AllCMPClass [21]: = TMEMO;

AllCMPClass [22]: = Tsplitter;

AllCMPClass [23]: = Tcheckbox;

AllCMPClass [24]: = TEDIT;

AllCMPClass [25]: = TListBox;

AllCMPClass [26]: = TcomboboX;

AllCMPClass [27]: = TDATETIMEPICKER;

AllCMPClass [28]: = TIMAGEBUTTON

AllCMPClass [29]: = TTABSET;

AllCMPClass [30]: = TTREEVIEW;

AllCMPClass [31]: = TLISTVIEW;

END;

Procedure RegisterallClasses (aallcmpclass: tallcomponentclass);

VAR

i: integer;

Begin

For i: = 0 to registeredcompoentclasscount-1 do

RegisterClass (AallCMPClass [i]);

END;

Procedure UnregisterallClasses (aallcmpclass: tallcomponentclass);

VAR

i: integer;

Begin

For i: = 0 to registeredcompoentclasscount-1 do

UnregisterClass (aallcmpclass [i]);

END;

Function ComponentTostring (Component: Tcomponent): String;

VAR

Binstream: TMemoryStream;

Strstream: Tstringstream;

String;

Begin

Binstream: = TMEMORYSTREAM.CREATE;

Try

Strstream: = TSTRINGSTREAM.CREATE (S);

Try

Binstream.writeComponent (Component);

Binstream.seek; 0, Sofrombeginning;

ObjectBinaryTotext (Binstream, strstream);

Strstream.seek (0, SOFROMBEGINNIN);

Result: = strstream.datastring;

Finally

STRSTREAM.FREE;

END;

Finally

Binstream.free

END;

END;

Function stringtocomponent (value: string; instance: tcomponent): tComponent

VAR

Strstream: Tstringstream;

Binstream: TMemoryStream;

Begin

Strstream: = TstringStream.create (Value);

Try

Binstream: = TMEMORYSTREAM.CREATE;

Try

ObjectTextTobinary (Strstream, Binstream);

Binstream.seek; 0, Sofrombeginning;

Result: = binstream.readComponent;

Finally

Binstream.free;

END;

Finally

STRSTREAM.FREE;

END;

END;

Function getObjectString (list: tstrings; begline: integer = 0; typeString: String = ''): string;

VAR

I, Ibegcount, Indcount: Integer;

Objstring, Line, ClassStr: String

Begin

Ibegcount: = 0;

IENDCOUNT: = 0;

ClassStr: = Trim (Uppercase (TypeString));

For i: = begline to list.count-1 do

Begin

Line: = Uppercase (List [i]);

IF POS ('Object', Line)> 0 THEN

Begin

IF (TypeString = '') or (POS (':' ClassStr, Line)> 0) THEN

IBEGCOUNT;

end

Else if (ibegcount> ipcount) and (Trim (trim (line) = 'end') THEN

INC (IENDCOUNT);

IBEGCOUNT> 0 THEN

Result: = Result List [i] # 13 # 10;

IBEGCOUNT> 0) and (ibegcount = ipcount) THEN

EXIT;

END;

END;

Procedure deleteErrorLines (List: tstrings);

VAR

i: integer;

Line: String;

Begin

if list.count = 0 THEN

EXIT;

I: = 0;

While i

Begin

Line: = trim (List [i]);

IF Copy (Line, 1, 2) = 'on' Then

List.delete (i)

Else

INC (I);

END;

END;

Procedure readform (AFILOM: TComponent; AfileName: String = ');

VAR

FRMSTRINGS: TSTRINGS;

Begin

RegisterClass (TPERSISTENTCLASS (AFROM.CLASSTYPE);

FRMSTRINGS: = TSTRINGLIST.CREATE;

Try

if Trim (AfileName) = '' Then frmstrings.loadfromfile (GSPATHINFO '/' AFROM.NAME '. TXT')

Else frMstrings.loadfromfile (afilename);

While Afrom.comPonentcount> 0 do afrom.components [0] .destroy;

AFROM: = StringTOComponent (frMstrings.text, afrom)

Finally

FRMSTRINGS.FREE;

END;

UnregisterClass (TPERSISTENTCLASSTY); END;

Function loadTextform (filename: string): tform;

VAR

List: tstrings;

Firstline: String;

IPOS: Integer;

Form: TForm;

Begin

Result: = NIL;

If FileExists (filename) = false then

EXIT;

Form: = tForm.create (Application);

List: = TSTRINGLIST.CREATE;

Try

List.loadfromfile (filename);

if list.count = 0 THEN

EXIT;

Firstline: = List [0];

IPOS: = POS (':', firstline);

If ipos = 0 THEN / / Can't find ':', format is not

EXIT;

List [0]: = Copy (Firstline, 1, IPOS) 'TFORM';

DeleteErrorLines (List);

StringTOComponent (list.text, form);

Result: = form;

Except

Form.free;

Result: = NIL;

END;

List.free;

END;

Function LoadTextform2 (filename: string; out errmsg: string): TForm;

VAR

List: tstrings;

Firstline: String;

IPOS: Integer;

Form: TForm;

Begin

Result: = NIL;

If FileExists (filename) = false then

Begin

Errmsg: = 'invalid file name! "

EXIT;

END;

Form: = tForm.create (Application);

List: = TSTRINGLIST.CREATE;

Try

List.loadfromfile (filename);

if list.count = 0 THEN

EXIT;

Firstline: = List [0];

IPOS: = POS (':', firstline);

If ipos = 0 THEN / / Can't find ':', format is not

Begin

Errmsg: = 'Can't find' ':' ', file format is not right;

EXIT;

END;

List [0]: = Copy (Firstline, 1, IPOS) 'TFORM';

DeleteErrorLines (List);

StringTOComponent (list.text, form);

Result: = form;

Except

ON E: Exception DO

Begin

Form.free;

Result: = NIL;

Errmsg: = 'Read file error:' E.Message;

END;

END;

List.free;

END;

INITIALIZATION

Begin

InitclasStype (AllCMPClass);

RegisterallClasses (AllCMPCLASS);

END;

Finalization

UnregisterallClasses (AllCMPClass); END.

转载请注明原文地址:https://www.9cbs.com/read-20382.html

New Post(0)