Author: Tomas Rutkauskas
How to create data-aware components
Answer:
This document describes minimal steps necessary to create a data-aware browsing
component that displays data for a single field. The example component is a panel
with DataSource and DataField properties similar to the TDBText component. See the
Component Writer's Guide "Making a Control Data-Aware" for further examples.
Basic steps to create a data-browsing component
Create or derive a component that allows the display, but not the entry of data.
For instance, you could use a TMemo with ReadOnly set to true. In the example
outlined in this document, we'll use a TCustomPanel. The TCustomPanel will allow
display, but not data entry.
Add a data-link object to your component. This object manages communication between
the component and the database table.
Add DataField and DataSource properties to the component.
Add methods to get and set the DataField and DataSource.
Add a DataChange method the component to handle the data-link object's OnDataChange
event.
Override the component constructor to create the datalink and hook up the
DataChange method.
Override the component destructor to cleanup the datalink.
Creating the TDBPanel
Create or derive a component that allows the display, but not the entry of data.
We'll be using a TCustomPanel as a starting point for this example.
Choose the appropriate menu option to create a new component (this will vary
between editions of Delphi), and specify TDBPanel as the class name, and
TCustomPanel as the Ancestor type. You may specify any palette page.
Add DB and DBTables to your Uses clause.
Add a data-link object to the components private section. This example will display
data for a single field, so we will use a TFieldDataLink to provide the connection
between our new component and a DataSource. Name the new data-link object
FDataLink. Example:
1
2 private
3 FDataLink: TFieldDataLink;
Add DataField and DataSource properties to the component. We will add supporting
code for the get and set methods in following steps. Note: Our new component will
have DataField and DataSource properties and FDataLink will also have its own
DataField and Datasource properties. Example:
4
5 published
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write SetDataSource;
Add private methods to get and set the DataField and DataSource property values to
and from the DataField and DataSource for FDataLink. Example:
6 private
7 FDataLink: TFieldDataLink;
8
9 function GetDataField: string;
10 function GetDataSource: TDataSource;
11 procedure SetDataField(const Value: string);
12 procedure SetDataSource(Value: TDataSource);
13
14 implementation
15
16 function TDBPanel.GetDataField: string;
17 begin
18 Result := FDataLink.FieldName;
19 end;
20
21 function TDBPanel.GetDataSource: TDataSource;
22 begin
23 Result := FDataLink.DataSource;
24 end;
25
26 procedure TDBPanel.SetDataField(const Value: string);
27 begin
28 FDataLink.FieldName := Value;
29 end;
30
31 procedure TDBPanel.SetDataSource(Value: TDataSource);
32 begin
33 FDataLink.DataSource := Value;
34 end;
Add a private DataChange method to be assigned to the datalink's OnDataChange
event. In the DataChange method add code to display actual database field data
provided by the data-link object. In this example, we assign FDataLink's field
value to the panel's caption. Example:
35
36 private
37
38 procedure DataChange(Sender: TObject);
39
40 implementation
41
42 procedure TDBPanel.DataChange(Sender: TObject);
43 begin
44 if FDataLink.Field = nil then
45 Caption := '';
46 else
47 Caption := FDataLink.Field.AsString;
48 end;
Override the component constructor Create method. In the implementation of Create,
create the FDataLink object, and assign the private DataChange method to
FDataLink's OnDataChange event. Example:
49 public
50
51 constructor Create(AOwner: TComponent); override;
52
53 implementation
54
55 constructor TMyDBPanel.Create(AOwner: TComponent);
56 begin
57 inherited Create(AOwner);
58 FDataLink := TFieldDataLink.Create;
59 FDataLink.OnDataChange := DataChange;
60 end;
Override the component destructor Destroy method. In the implementation of Destroy,
set OnDataChange to nil (avoids a GPF), and free FDatalink. Example:
61 public
62
63 destructor Destroy; override;
64
65 implementation
66
67 destructor TDBPanel.Destroy;
68 begin
69 FDataLink.OnDataChange := nil;
70 FDataLink.Free;
71 inherited Destroy;
72 end;
Save the unit and install the component (see the Users Guide, and the Component
Writers Guide for more on saving units and installing components).
To test the functionality of the component, add a TTable, TDatasource, TDBNavigator
and TDBPanel to a form. Set the TTable DatabaseName and Tablename to 'DBDemos' and
'BioLife', and the Active property to True. Set the TDatasource Dataset property to
Table1. Set the TDBNavigator and TDBPanel DataSource property to Datasource1. The
TDBpanel DataField name should be set as 'Common_Name'. Run the application and use
the navigator to move between records to demonstrate the TDBPanel's ability to
detect the change in data and display the appropriate field value.
Full source listing:
73 unit Mydbp;
74
75 interface
76
77 uses
78 SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
79 Controls, Forms, Dialogs, ExtCtrls, DB, DBTables;
80
81 type
82 TDBPanel = class(TCustomPanel)
83 private
84 FDataLink: TFieldDataLink;
85 function GetDataField: string;
86 function GetDataSource: TDataSource;
87 procedure SetDataField(const Value: string);
88 procedure SetDataSource(Value: TDataSource);
89 procedure DataChange(Sender: TObject);
90
91 public
92 constructor Create(AOwner: TComponent); override;
93 destructor Destroy; override;
94 published
95 property DataField: string read GetDataField write SetDataField;
96 property DataSource: TdataSource read GetDataSource write SetDataSource;
97 end;
98
99 procedure register;
100
101 implementation
102
103 procedure register;
104 begin
105 RegisterComponents('Samples', [TDBPanel]);
106 end;
107
108 function TDBPanel.GetDataField: string;
109 begin
110 Result := FDataLink.FieldName;
111 end;
112
113 function TDBPanel.GetDataSource: TDataSource;
114 begin
115 Result := FDataLink.DataSource;
116 end;
117
118 procedure TDBPanel.SetDataField(const Value: string);
119 begin
120 FDataLink.FieldName := Value;
121 end;
122
123 procedure TDBPanel.SetDataSource(Value: TDataSource);
124 begin
125 FDataLink.DataSource := Value;
126 end;
127
128 procedure TDBPanel.DataChange(Sender: TObject);
129 begin
130 if FDataLink.Field = nil then
131 Caption := ''
132 else
133 Caption := FDataLink.Field.AsString;
134 end;
135
136 constructor TDBPanel.Create(AOwner: TComponent);
137 begin
138 inherited Create(AOwner);
139 FDataLink := TFieldDataLink.Create;
140 FDataLink.OnDataChange := DataChange;
141 end;
142
143 destructor TDBPanel.Destroy;
144 begin
145 FDataLink.Free;
146 FDataLink.OnDataChange := nil;
147 inherited Destroy;
148 end;
149
150 end.
|