Delphi production data perceived control
Wang Weicang
Knowledge point
This article has 6 knowledge points on controls:
1. Production of basic controls; 2. Perceive the addition of attributes; 3. Destruction processing of related controls;
4, the assignment of the event method; 5, the property page is produced; 6, components package design ideas
There are many articles about making a perceptual control, but most of the content involved is more than one, the reader can only operate according to the statement of the article, and it is unable to understand the production mechanism of the control. This article tries to focus on the ideas and programming ideas of making a sense control by explaining a control, let the reader really understand the production mechanism of the VCL control, rather than just understand the production method of this control, I hope to make readers to read In the future, I reached the effect of "one leaf and see the sky", ha, exaggerated.
This article is made as an example of a control similar to DBEDIT. First, use the Component Wizard from TEDIT to inherit, named TMYDATABASEEDIT, the unit name is MyDatabaseedi.PAS, installed in a new package file, named myDataEditstd60.dpk.
There is no rule, but we recommend compliance with the name of the package: the name of the package is related to the package of the package, the front of the package usually represents the author or company name, or a descriptor of the control, followed by the back STD represents the running period, DSGN represents the design package, then the version number. We will subsequently explain the designs.
Data perception
Ready, we start editing the functionality of the control, first add data source sensation attributes. Datasource, implement this property, simply add one sentence to the Pubished domain:
Property Datasource: TDataSource ReadDataSource Write setDataSource; Press the automatic structured function of the SHIFT CTRL CURSOR to complete the properties, the private domain automatically adds two functions:
Procedure setDataSource (const value: tdataser);
Function getDataSource: TDataSource;
This way, install the components to the panel, you can see that the component already has .DataSource properties, and realize the TDataSource control function. How, simple, huh, huh. In fact, we can get this: The perception of the control attribute is just that a property declared as the control class that will be perceived. If the image control is perceived, then:
Property MyImage: TIMAGE Read GeTImage Write setImage;
However, if we want to use a control as the subtribracle of this control, the code of the two controls is merged, and the above sentence cannot be required only:
First, remove the registration function of the added control;
Second, inherit it from Tcomponent inherited from TPERSISTENT. Let's try it.
Event assignment
However, this control does not really connect with the database, just one look, to really implement the function, we need to add code, then we use an important class TFieldDataLink.
It is a data link object inside the control, inheriting from TDATALINK, and its role is to communicate with TDataSource components and connect a single field for data extraction. We will handle the OONDATAANGE event of this object, so that when the field or record changes, the corresponding data processing is performed. OK, we declare objects and create: Private domain declaration fdataLink: TfieldDataLink; created in constructor
Constructor TMYDATABASEEDIT.CREATE (Aowner: Tcomponent);
Begin
inherited;
FDATALINK: = TfieldDataLink.create;
FDATALINK.ONDATACHANGE: = Datachange;
END;
Datachange is a process of our Private domain statement: Procedure Datachange (Sender: TOBJECT); this implements the actual function of our control and connects to the fdataLink.OndaChange event. After creating success, we implements getDataSource, setDataSource function process:
Function TMYDATABASEEDIT.GETDATASOURCE: TDATASOURCE
Begin
Result: = fdataLink.datasource;
END;
Procedure TMYDATABASEEDIT.SETDATASOSOSEEDIT.SETDATASOURCE (Const Value: TDataSource);
Begin
IF not (fdataLink.datasourcefixed and (cslineing in componentstate)).
Begin
FDATALINK.DATASOURCE: = Value;
END;
IF value <> nil kil
Begin
Value.Freenotification (Self);
END;
END;
Destruction of related control
The above code is implemented so that the data is truly associated with the control, and the code to add the DataChange process to personalize processing data.
So what does value.freenotification (self) code mean? Please think about it: Our components need to be combined with the DataSource control and DataSet control to implement the reading and writing of database data, then when we delete one of them, if the other two controls don't know, then will it still abnormally? The answer is yes.
So how can we notify other components? Yes, value.freenotification (self) is doing this work! FreeNotification (Self) will place our components into its notification object list, when it is revoked, it calls the Notification method of all objects in the notification object list, we only need to overload it in the component:
protected
{Protected Declarations}
Procedure Notification; Operation: TOPERATION; OVERRIDE;
The code is implemented as follows:
Procedure TMYDATABASEEDIT.NOTIFICATION (ACOMPONENT: TComponent;
Operation: TOPERATION);
Begin
Inherited NOTIFICATION (ACOMPONENT, OPERATION);
IF (Operation = Opremove) and (fdataLink <> nil) and (attomponent = datasource). DataSource: = NIL;
END;
Thus, when the associated reference control is deleted, the control will get a message to handle the event, prevent an abnormality, otherwise it will cause the Delphi development environment unstable or even crash, remember!
At the same time, don't forget to overload the Destroy function:
Destructor TMYDATABASEEDIT.DESTROY;
Begin
inherited;
FDATALINK.FREE;
FDATALINK: = NIL;
END;
Make sure you destroy the FDATALINK instance, release the space. Whether it is write components or writing programs, we must strictly pay attention to the object of statements, be sure to release it after use!
Add a DataField property
We use this control to connect to the Database component, display its field value in Edit.Text by selecting the field name. Then we are still missing. Datafield.
Published domain statement:
Property DataField: String ReadfieldName Write setfieldname
The implementation is as follows:
Function TMYDATABASEEDIT.GETFIELDNAME: STRING
Begin
Result: = fdataLink.fieldName;
END;
Procedure TMYDATABASEEDIT.SETFIELDNAME (Const value: string);
Begin
FDATALINK.FIELDNAME: = Value;
END;
OK, such a field in the database will be listed in the drop-down box.
Below we fill in our data processing process:
Procedure TMYDATABASEEDIT.DATACHANGE (Sender: TOBJECT);
Begin
IF fdataLink.field <> nil dam
Begin
Text: = fdataLink.field.text;
END;
END;
Ha, now it is basically running. Now, we connect Table, DataSource, to see that when the current record changes, the field value of the selected field is displayed in the Edit box of the MyDatabaseEdit control.
Add Properties page (About)
Now the basic function has already been available. Here we give it a property page, we just do an About dialog presentation, developers can customize themselves according to their actual features.
The effect we implemented is required: an About property appears in the property editing browser, the right side is displayed: (About) ... Click the "..." button to pop up a dialog.
Below we started to create a new package, name the naming rule: mydataeditdsgn60.dpk, then create a new form, as the About dialog, we can design the interface as needed. We create a new class TaboutEditor to inherit it from TPropertyEditor:
TabOUtedit = Class (TPropertyEditor)
FFRMabout: tfrmabout;
Function GetAttributes: tpropertyAttributes; Override;
Function GetValue: String; Override;
保RIDE;
Note: Delete the global FORM variable and re-declare a new private variable in the TaboutET class.
Override Edit function:
Procedure taboutit.edit;
Begin
Ffrmabout: = TfrmAbout.create (Application);
FfrmAbout.ShowModal;
Ffrmabout.free
END;
Used to create a destroy form object.
Override GetAttributes function:
Function TaboutIt.gettributes: tpropertyAttribute;
Begin
Result: = [Padialog, PareadOnly];
END;
Tell IDE to display what work will be displayed, about TPROPERTYATTRIBUTES can be referred to with help, and will not be described here. We are displayed in the way in just read dialogs, and the Object Inspector will appear a omitted button next to the About property. When the user clicks this button, call the Edit method.
Cover the getValue function, which is the word "(About), and read only by omitting the number button.
Function Taboutit.getValue: String;
Begin
Result: = '(About)'
END;
Ok, work is basically complete, if you want to further control, you can also study the code of the TPropertyEditor class. It is not fine here.
Maybe you have doubt: Can this? How does the control know this package property method, it is not associated. By the way, you have to associate editors and controls.
1, the control adds a string type "about" attribute
2, register attribute editor in the unit of the editor
The first step is very simple, and everyone is familiar with the method of adding an attribute:
Private
Fabout: String
Published
Property About: String Read Fabout Write Fabout;
Step 2, just add a registered global process function in the attribute editor unit:
Procedure register
Beguing
// There is only one sentence:
RegisterPropertyEditor (TypeInfo (String), TMYDATABASEEDIT, 'About', Taboutedit;
END;
Now, let me explain the RegisterPropertyEditor function: it is used to register an attribute editor to associate an attribute and editor in the control.
l First parameter: typeInfo (String), Parameter prototype: PropertyType: PtypeInfo It is a pointer, pointing to the runtime type information of the attribute to be edited, we get TypeInfo ().
l Second parameters: TMYDATABASEEDIT, Parameter prototype: Component: CALSS, used to specify the component class to which this property editor is.
l The third parameter is a string that specifies the name of the active attribute.
l The fourth parameter is used to specify the type of the attribute editor.
If the second parameter is set to NIL, the third parameter is set to an empty string, what will be? Hey, all the properties of all String types becomes a About box, haha.
Everyone pays that we are just simply making an About dialog, the purpose is to make everyone quickly clearly understand the design principles of the attribute editor, we can also make it complex a complex dialog box, This way we can really use the dialog to edit the properties of the control. It is necessary to see the actual needs, but don't leave the Zong, huh, huh. If you are interested, you can also study the StringSedit unit under Delphi's Source / Property Editors directory. (Various types of properties editor, definitions can refer to the "Delphi5 Developer Guide" Part II "Development of Components" or Cractive Designeditors Unit)
Design idea
We have built a package component package when the editor is designed. Components package, everyone should understand it, it is similar to DLL, but it is only common in Delphi and CBuilder environments. Very good use of this package, you can make our program module clear, maximize code reuse, so that the volume of the program is as low as possible, and can be used in these two locale. There are not many sayings here, otherwise it will run too far, if you are interested, you can contact me, discuss together.
Now, let me say why you want to open the control package, and create a package component package separately.
First, the block is divided into management. This doesn't have to say more, a running period, a design package, making the application's volume becomes small, save all of the units all links to the execution program (Delphi5 pre-versions) Even if you only link in the program, the code when mixing the run and the design will also expand your code. Because your design code will not be executed at runtime, but the compiler doesn't know, so it will also link it together.
One of the facts is that the VCL structure has been adjusted since Delphi6, and Borland replaces DSgnintf with Designintf, and the attribute editor is also placed in Designeditors, DesignMenus, DesignWindows and other design files. In particular, Designeditors uses other IDE files called Proxies. And PROXIES is compiled into the Designide.bpl file. Designide.bpl is no longer a file that can be distributed, we can only use it in the development environment, do not say, when compiling the application, there is a problem that "can't find the file". At this time, we separate the running period and the design period, join the design period to the designide.dcp file, compile the package file, and ensure that it is correct, compiled!
So we abide by some agreements will make our code structure to optimize, generally set as follows:
Design costumes should include:
1. All registration declarations (preferably in a separate unit);
2, all attribute editing;
3. All component editors;
4, will require Designide support package.
Note: The Component Editor is a shortcut menu on the component, like Table and other components. Its production is similar, which is inherited from TcomponenTeditor. There is no more talks here.
Runtime packs should include:
1, the component itself.
2. Components may be called in the runtime (used by the property editor).
Package Sections For different versions, Delphi 6.0's editor version is VER140, the editor version of Delphi 5.0 is VER130, if we want to adapt to different versions to use {$ IFDEF VER140}. . . {$ ELSE}. . . {$ ENDIF}; Control in the Uses domain, this is a little attention. The above is my experience in the experience of Delphi production data, I hope I can give you a little inspiration, and bend less on the road to development. Welcomes everyone ax, welcome everyone to discuss! My email: weikang_wang@163.com