Wu Zeping (Renqiu City, Hebei Province)
---- One. How to use tree control in Delphi
- - We all know that developers mainly use Delphi to develop database management software, because of this, the use of tree controls is best linked to the database. Delphi provides a tree control TTREEVIEW that can be used to describe complex hierarchical relationships.
---- 1. Storage and loading of tree node information
---- Common way is to achieve interaction between tree controls and files with tree controls; or use ASSIGN methods to implement tree controls and dbmemo, which is interact with the database. The advantages of this method are relatively simple programming. The disadvantage is that the number of actual nodes of tree controls may be large. For "big trees", the amount of data per load and storage will increase, will reduce the speed, increase system overhead, resulting Data redundancy. Another method is to generate "see" nodes on the tree, and there is no file or database field that specifically records all tree node structures, and disperse the tree node structure in each record of the database.
---- Specific method is: Create a database, the field is determined according to the actual business, where information will be displayed on the node of the tree control, and one field is also a field to save the unique identification number of the node. The identification number consists of two parts equal to the length, the front segment represents the parent node number of the current node, indicating the node number of the current node, this identification number corresponds to a "linked list", records the structure of the tree node. The advantage of this method: When the user operates "big tree", all nodes generally do not expand, and only a limited part is used, and can only be launched from one layer of the root, which is only generated on the tree. " See the node, so store and load the "big tree" fast, small data amount, system overhead, and data redundancy. Disadvantages: Complicated programming, but can be combined into a new tree control, which will greatly improve programming efficiency. It is worth noting that the ID number must be unique, so how to generate IDs reasonably in the programming.
---- 2. Database Structure Example
---- Create a database to simplify the program, I only create two database fields, defined as follows:
Field name type length
TEXT C 10
Longid C 6
---- LongID field is actually composed of two sections, each 3 digits, longid can only represent 1000 records. Define LongID as an index field, saving C: /TestTree/tree.dbf. Edit the DBF file, create a record, the Text field is set to top, the longID field is set to "000" (3 "0" three spaces).
---- 3. Creating a demo program
---- Place TreeView1, Table1, PopupMenu1, Edit1, and Edit2 on Form1. TreeView1's PopupMenu property is set to popupMenu1; Table1's DatabaseName property is set to the C: / Testtree property set to Tree.dbf, the indexfieldnames property is set to LongID; PopupMenu1 is selected for the single add1 and del1, CAPTION is Add and DEL; Edit1, respectively Used to enter the text attribute value of the new node, edit2 is used to enter the 3-digit ID number of the new node. Save C: /TestTree/treeUnit.PAS and C: /TestTree/testtree.dpr. Add a line after Type of TreeUnit.PAS: PSTR: ^ string; {PSTR is a string pointer} to Form1's oncreate event Add code: Procedure TFORM1.MMCREATE (Sender: TOBJECT);
VAR P: PSTR; Node: ttreenode;
Begin
With Table1, TreeView1 DO
Begin
Open;
First;
NEW (P); {Pointer P Distributed Memory}
P ^: = FieldByname ('longid'). asstring;
Node: = items.addchildObject (nil, fieldbyname
('Text'). Asstring, p);
IF Hassubindbf (Node) Then Items
.AddchildObject (node, '', nil); {has a child node plus an empty node}
END;
END;
---- Hassubindbf is a custom function, the argument is Node, checks the node Node Node, and there is a return to True, and then return false, and join the prototype declaration in the class definition of TForm1 (other custom function prototype In the class definition of TForm1, the function code is as follows:
Function TFORM1.HASSUBINDBF (Node: ttreenode): boolean;
Begin
With table1 do
Begin
Table1.Findnearest ([Copy (PSTR (Node.Data) ^, 4, 3) '000']);
Result: = COPY (FieldByName ('longid').
Asstring, 1, 3) = Copy (PSTR (Node.Data) ^, 4, 3);
{, Such as the top 3 bits of the content of the LONGID field recorded in the database
After the Node Node's DATA is the same, then Node should have subpasis}
END;
END;
Add a code to the Ondeletion event for the TreeView1 control, you need to point out,
Not only calls the delete method, but the ONDLETION event can be triggered, but also before the tree control itself is released.
Also triggered an OONELETION event, so add Dispose (Node.Data) here will be "secure":
Procedure TFORM1.TREEVIEW1DELETITION
(Sender: Ttreenode);
Begin
Dispose (Node.Data); {Release Node Data Memory}
END;
Add code to an onClick event for add1 options as follows:
Procedure TFORM1.ADD1Click (Sender: TOBJECT);
VAR P: PSTR; TMPSTR: STRING; i: integer;
Begin
Try
STRTOINT (edit2.text); tmpstr: = edit2.text; {Note: In practical, you must use a better way to generate id}
Except;
ShowMessage ('re-entering Edit2 content');
Abort;
END;
With TreeView1 Do
Begin
NEW (P);
P ^: = Copy (PSTR (SELECTED.DATA) ^, 4, 3) TMPSTR;
Items.addchildObject (SELECTED, EDIT1.TEXT, P);
END;
With table1 do {Add records in the database}
Begin
Append;
FieldByname ('text'). Asstring: = edit1.text;
FieldByName ('longid'). Asstring: = p ^;
POST;
END;
Tmpstr: = INTOSTR (STRTOINT (TMPSTR) 1);
For i: = length (tmpstr) to 2 do tmpstr: = '0' tmpstr;
Edit2.Text: = Tmpstr;
END;
Add code to the DEL1 menu item to add code as follows:
Procedure TFORM1.DEL1CLICK (Sender: TOBJECT);
Var Dellist: tstringlist; longid, nsublongid: String;
Begin
Dellist: = TSTRINGLIST.CREATE;
Dellist.sorted: = TRUE;
Dellist.add (pstr (treeview1.selected.data);
While Dellist.count> 0 do
Begin
Longid: = Dellist.strings [0];
Dellist.delete (0);
Table1.setKey;
Table1.fieldbyName ('longid'). Asstring: = longId;
if Table1.gotoKey There1.delete;
IF Hassubindbf (TreeView1.Selected) THEN
Begin
NSUBLONGID: = Table1.fieldByName ('longid'). Asstring;
While (Copy (NSUBLONGID, 1, 3) = COPY
(LongID, 4, 3)) and (not Table1.eof) DO
Begin
Dellist.add (nsublongid);
Table1.next;
NSUBLONGID: = Table1.fieldByName ('longid'). Asstring;
END;
END;
END;
Dellist.free;
TreeView1.Items.delete (TreeView1.Selected);
END;
Add code to TreeView1 onExpanding event:
Procedure TFORM1.TREEVIEW1EXPANDING
(Sender: TTREENODE);
VAR AllowExpansion: Boolean;
VAR TMPNODE: TTREENODE; NSUBLONGID:
String; p: pstr; bm: tbookmark;
Begin
With Table1, TreeView1 DO
Begin
Items.beginupdate;
SetKey;
FieldByname ('longid'). Asstring: = pstr (node.data) ^;
IF not gotokey kiln it items.delete (Node)
Elsebegin
TmpNode: = node.getfirstchild;
IF (TmpNode.Text = ') and (tmpnode.data = nil) THEN
Begin
TmpNode.delete;
IF Hassubindbf (Node) THEN
Begin
NSUBLONGID: = FIELDBYNAME ('longid'). Asstring;
While (Copy (NSUBLONGID, 1, 3) = COPY (PSTR
(Node.Data) ^, 4, 3)) And (not EOF) DO
Begin
NEW (P);
P ^: = FieldByname ('longid'). asstring;
BM: = GetBookmark;
TmpNode: = items.addchildObject (Node,
FieldByname ('text'). Asstring, p);
IF Hassubindbf (TmpNode).
AddChildObject (TmpNode, '', NIL);
Gotobookmark (BM);
FreebookMark (BM);
NEXT;
NSUBLONGID: = FIELDBYNAME ('longid'). Asstring;
End; end;
END;
Items.endupdate;
END;
END;
---- The basic method of talking about the tree display of the database is briefly discussed. In addition, the TEXT attribute of the tree node is edited, and the database is modified while the same database is operated at the same time, the database and the consistency of the tree. The copy and replication of the upper node will not be described again, readers can improve their own.
---- II.IP control
---- In the network program, we often encounter the case where you need the user to enter the IP address. However, Delphi does not provide us with controls that can be used to enter IP strings so we have to accept the IP string input by the TEDIT control (single line text box). However, using TEDIT to enter an IP string is not a good idea because it is very inconvenient. In fact, there is a Windows control specifically used to enter the IP string next to our side. The IP control will reject the illegal IP string (only the number between 0,255); it allows you to easily get the IP value corresponding to the IP string in the control (32-bit integers), this The province has saved the trouble between IP strings and IP values; in addition, you can limit the range of IPs that can be entered in the IP control. This section describes how to use Windows IP controls in our Delphi program.
---- There are two very important dynamic linkages in Windows: CommCtrl.dll and ComctL32.dll, which are Windows Common Controls. The custom control library contains many common Windows controls, such as Statusbar, Coolbar, Hotkey, etc .; most of these controls have been packaged into visual controls in Delphi. After Microsoft launches Internet Explorer 3, some controls have been added to the custom control library, including the IP Address Edit Control.
---- 1. Initialize Windows Custom Control Library
---- Windows provides two API functions, INITCOMMONCONTROLS, and INITCOMMONCONTROLSEX to initialize custom control libraries. From the name, we are not difficult to see the relationship between these two API functions: the latter is the enhancement of the former. If you want to use IP controls in the program, you must use INTCOMMONCONTROLSEX to complete the initialization of custom control libraries and classes. The prototype of the function initcommonControlsex is as follows (Pascal syntax): ... ...
Create an IP control
...
Use IP controls. In the program, we communicate with it by sending messages to the IP control.
There are 6 messages that IP controls can respond, these messages and their meaning are shown in the table:
...
To get the IP value corresponding to the IP string in the IP control, you should send the IP control
IPM_Getaddress message, and need to put a 32-bit integer
The last parameter of SendMessage.
...
---- 2. Notification message for IP control
---- When the IP string is changed or the input focus occurs, the IP control sends a notification message ipn_fieldchanged to its parent window. In most cases, we can ignore this notification message. The following is an example of the processing notification message IPN_FIELDCHANGED:
Procedure TFORM1.WNDPROC (VAR Msg: TMESSAGE);
Var P: pnmhdr;
Begin
inherited;
IF msg.msg = wm_notify
Then Begin
P: = Pointer (msg.lparam);
IF P ^ .code = ipn_fieldchanged
Then Begin
{...
Processing IPN_FieldChanged Notification Messages for IP Controls
...}
END;
END;
END;
---- II. Method and application of dynamic generating control
---- Two methods of generating controls in Delphi
---- (1). Form (Form) Generate Controls
---- When performing Form design, select the required control directly in the control toolbox, then set its properties and response events, this method is more common.
---- (2). Dynamic generation controls in the program
---- Sometimes we need to dynamically generate controls during program runtime, do two advantages: First, you can add the flexibility of the program; if the generated control is related to the intermediate operation results of the program, obviously method It is impossible to implement, must be dynamically generated in the program.
--- The method of dynamically generating controls in the program is divided into three steps. First, define the generated control type, then generate controls with the CREATE function, and finalize the relevant attributes of the control. Take the TBUTTON control as an example, the steps are as follows:
---- a. Define control types
VAR
Button1: tbutton;
---- b. Generate controls
Button1: = TButton. Create (Self);
Button1.parent: = Self;
/ / Generally set its parent control to Self, if the value of the Parent is not set,
The control will not be on the screen
//show
---- c. Set other properties and definition related event response functions, such as CAPTION, LEFT, TOP, HEIGHT, WIDTH, Visible, Enabled, Hint, and OnClick event response functions.
---- 2. Application of Dynamic Generation Control Method
---- In the development and production scheduling and management system, it is necessary to dynamically generate an exclusive production plan. Taking the Gantt chart, applying the Shape control to display parts processing status (processing start time and end time of each process) is very suitable. Applying a Chart control to the processing equipment utilization is displayed in three-dimensional straightner graph, it is very intuitive. The process of dynamically generating a Shape control and a CHART control in the program will be described. ---- (1). Dynamic Generate Shape Control Shows Excunization Plan (Gantt Chart)
Procedure Tcreatemulticharts.ProccreateCharts;
VAR
I, J, Rows, Column, Rowspace, Chartsheight: Integer
Shapechart: Array of Array of Tshape;
Begin
Rows: = 16; // SHAPE control array number
Columns: = 8; // Shape control array number
ROWSPACE: = 20; // Shape control line spacing
Chartsheight: = 20; // Shape control height
SETLENGTH (ShapeChart, Rows, Column);
// Set the size of the ShapeChart array
For i: = 0 to rows do
For j: = 0 to columns do
Begin
ShapeChart [I] [J]: = Tshape.create (Self);
With shapechart [i, j] do
Begin
Parent: = Self; // This trip is essential,
Otherwise, the Shape control does not display it on the screen.
Shape: = strectangle; // shape control shape is rectangular
Top: = 45 i * (ROWSPACE ChartsHeight);
Left: = ROUND (180 Q [i, j] .starttime);
// Due to Q [i, j] .starttime is the real number, it is necessary to carry out round
Width: = ROUND (q [i, j] .value)
Height: = chartsheight;
Brush.color: = randomcolor;
/ / Customize the function, after the attachment
Brush.style :=bssolid; // Set the fill method
Enabled: = TRUE;
END;
END;
END;
---- Note: A.Q is a recorded two-dimensional array, defined as follows:
Type
Tempdata = Record
VALUE: REAL;
STARTTIME: REAL;
END;
Q: Array of Array Of Tempdata
And the component of Q has been assigned in another process.
---- b. For different parts, Shape is displayed in different colors, and the function Randomcolor is called. This function is:
Function TCRETEMULTICHARTS.Randomcolor;
VAR
Red, Green, Blue: Byte
Begin
Red: = random (255);
Green: = random (255);
Blue: = random (255);
Result: = RED or (Green SHL 8) or (Blue SHL 16);
END;
---- (2). Dynamically generate ChartSeries components of Charts controls, display device utilization
Procedure TFormmultimachinesburthen.
ShowmachineburthenCharts;
VAR
i: integer;
SERIESCLASS: TCHARTSERIESCLASS;
Newseries: array of tchartseries;
Begin
SetLength (Newseries, Createmulticharts.Rows);
MachinesburthenCharts.Height: = 200;
MachinesburthenCharts.width: = 550;
For i: = 0 to createmulticharts.rows do
Begin
Seriesclass: = TBARSERIES; // Set shape is three-dimensional bar chart
Newseries [i]: = seriesclass.create (self);
Newseries [i] .parentchart: = MachinesburthenCharts;
Newseries [i] .clear;
Burthen: = Machineburthen [i];
Burthen: = round (burthen * 100) / 100; // only take two numbers after the decimal point
Newseries [i] .add (burthen, '', newseries [i] .seriescolor);
END;
END;
---- Note: (a) .MachineBurthen [i] is a real array, its value is the utilization of the corresponding device, has been calculated in another function;
---- (b). MachinesburthenCharts is a TCHART control, in the TYPE segment.
---- 3. Program operation results show
---- (1). Dynamically generate Shape controls, display parts exclusive production plan (omitted)
---- (2). Dynamically generate ChartSeries components of Chart control, display device utilization (omitted)