Li Xiaoping/North China Petroleum Workers University in Gu'an, Hebei Province
---- No matter what kind of program is developed, data input is indispensable. Quickly generating a beautiful input interface will undoubtedly greatly improve the efficiency of program development. The original controls of the system are often unsatisfactory. In Delphi, if it is for a certain field, the optional controls are DBLabel, DBEdit, etc.; if it is for the input of the entire table, there is DBGrid. When using controls such as Dbedit, users must fully arrange the positions of each field. Although it can achieve beautiful effects, it will undoubtedly be very troublesome if there are many fields. If DBGrid is used, no matter how many fields there are, only one control is enough. It is simple, but the fields are arranged one by one, which is a bit inconvenient to use. For ordinary users, input in table form is both convenient and beautiful. This is the problem this article aims to solve.
----Technical key
----The main function of this control is to edit database fields. According to general rules, the control should contain a TdataLink object and implement a series of methods related to TdataLink; however, that will consume a lot of code. The larger the amount of code, the more complex the system and the greater the potential for errors. The development idea of this control is to achieve the most functions with the least code. Therefore, edit data fields directly using the TDBComboBox control.
---- In order to achieve universality, a field editing control array and field title array are maintained inside the control. as follows:
Editors: array of TDBComboBox;
->A specific array of data controls used for editing, dynamically generated
Labels: array of TLabel;
->The title of each field is dynamically generated
----The advantage of using TDBComboBox is that it not only has general editing functions, but can also add corresponding prompt information to each field. The code is as follows:
{Method to add prompt information for field I}
PRocedure TDBPanel.AddHits
(ItemIndex: Integer; Hits: array of string);
var
m,n,i: Integer;
begin
n := Length(Editors);
m := Length(Hits);
if ItemIndex< n then begin
for i:=0 to m-1 do Editors[ItemIndex].Items.Add(Hits[i]);
end;
end;
---- Specific applications vary widely, so the control also needs to leave enough event processing interfaces for programmers to implement special functions for specific applications. This requires defining certain event processing methods in the control for users to implement. What is provided here is an OnOkClick event, which is the processing performed when all fields are edited. The code is as follows:
OkButton: TButton;
->The last added OK button is used to implement the submission action.
property OnOkClick: TNotifyEvent read FClick write FClick;
---- By implementing the OnOKClick method, users can complete various processing tasks such as submission and data rationality testing. Another thing that requires special treatment is controlling the conversion between various fields. The default is to click with the mouse. However, users' habit is often to use the four arrow keys "up, down, left, and right" on the keyboard. To implement this function, the following two methods need to be defined:
procedure AKeyPress(Sender: TObject; var Key: Char);
procedure AKeyDown(Sender: TObject;
var Key: Word; Shift: TShiftState);
---- Assign the above two methods to dynamically generated Editors to implement response to arrow keys.
---- Different tables have different numbers of fields, which may not be displayed, which requires a scrolling function. So, a TscrollBox control is inserted into the control. The last thing to note is the undoing of dynamic controls and the release of memory. The undoing of the control array and the release of memory are in order-the exact opposite order of creation. Otherwise something will go wrong.
----Use of controls
---- First place the DBPanel control on the form, and then set the data source properties, the number of columns of the data input form, and other properties. In the program, after opening the data source, just call the method to create the data editing control. Right now:
Query1.Open;->Open data source
DBPanel1.CreateEditors; ->Create edit controls for each field
DBPanel1.AddHits(0,['1111','11222','eeee']);
->Set prompt information for a certain field
DBPanel1.AddHits(1,['1111','11222','eeee']);
->Set prompt information for a certain field
The control and sample program have been debugged in the Win98+Delphi 5.0 environment.
---- Attachment: Source code of TDBPanel
unit DBPanel;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
ExtCtrls, dbctrls, stdctrls, db;
type
TDBPanel = class(TPanel)
private
{Private declarations}
FLeft: Integer;
FTop: Integer;
maxTextLen: Integer;
maxLabelLen: Integer;
FScrollBox: TScrollBox;{scroll control}
FLineHeight: Integer;
FClick: TNotifyEvent;
Editors: array of TDBComboBox;
->A specific array of data controls used for editing, dynamically generated
Labels: array of TLabel;
->The title of each field is dynamically generated
OkButton: TButton;
->The last added OK button is used to implement the submission action.
{data source}
FDataSource: TDataSource;
FColumns: Integer;
->Enter the number of columns of the table
protected
{ Protected declarations }
procedure FreeEditors;
->Release memory of data input control
public
procedure CreateEditors;//
(DS: TDataSource; ColCount: Integer);
->Create data input controls for each field
constructor Create(AOwner:
TComponent); override;
destructor Destroy; override;
procedure AKeyPress(Sender:
TObject; var Key: Char);
procedure AKeyDown(Sender:
TObject; var Key: Word; Shift:
TShiftState);
procedure ClearHits(ItemIndex: Integer);
procedure AddHits(ItemIndex:
Integer; Hits: array of string);
function Editor(Index: Integer):
TDBComboBox;
{Public declarations}
published
propertyLeftLimit: Integer read
FLeft write FLeft default 10;
property TopLimit: Integer read
FTop write FTop default 10;
property EditorLen: Integer read
maxTextLen write maxTextLen;
property LabelLen: Integer read
maxLabelLen write maxLabelLen default 100;
property LineHeight: Integer read
FLineHeight write FLineHeight default 15;
property OnOkClick: TNotifyEvent
read FClick write FClick;
property DataSource: TDataSource
read FDataSource write FDataSource;
->Data source
property Columns: Integer read
FColumns write FColumns;->number of table columns
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Additional', [TDBPanel]);
end;
{Method to add prompt information to field I}
procedure TDBPanel.AddHits(ItemIndex:
Integer; Hits: array of string);
var
m,n,i: Integer;
begin
n := Length(Editors);
m := Length(Hits);
if ItemIndex< n then begin
for i:=0 to m-1 do Editors[ItemIndex].Items.Add(Hits[i]);
end;
end;
procedure TDBPanel.AKeyDown
(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Sender is TDBComboBox) then begin
case Key of
VK_Next: (Sender as TDBComboBox)
.DataSource.DataSet.Next;
VK_PRIOR: (Sender as TDBComboBox)
.DataSource.DataSet.Prior;
end;
end;
end;
procedure TDBPanel.AKeyPress(Sender: TObject; var Key: Char);
begin
if (Sender is TDBComboBox) then begin
if Key=#13 then (Owner as TForm).Perform(WM_NEXTDLGCTL, 0, 0);
end;
end;
procedure TDBPanel.ClearHits(ItemIndex: Integer);
var
n: Integer;
begin
n := Length(Editors);
if ItemIndex< n then Editors[ItemIndex].Items.Clear;
end;
constructor TDBPanel.Create(AOwner: TComponent);
begin
Inherited Create(AOWner);
FLeft :=10;
FTop := 10;
maxTextLen := 100;
maxLabelLen := 100;
FLineHeight := 15;
end;
{Method to create data input controls for each field}
procedure TDBPanel.CreateEditors;//
(DS: TDataSource; ColCount: Integer);
var
i, n, RowCount: Integer;
TextHeight: Integer;
begin
if DataSource.DataSet.Active then begin
n := DataSource.DataSet.FieldCount;
{Calculate the maximum title length and display length}
DataSource.DataSet.First;
{calculate height}
TextHeight := Canvas.TextHeight(DataSource
.DataSet.Fields[0].DisplayLabel) + FLineHeight; //10;
{Calculate the number of rows and columns}
RowCount := n div Columns;
if n mod Columns < > 0 then inc(RowCount);
{Allocate memory}
FreeEditors;
SetLength(Editors, n);
SetLength(Labels, n);
{Create scroll box}
FScrollBox := TScrollBox.Create(Owner);
FScrollBox.Parent := Self;
FScrollBox.Align := alClient;
{CreateEdit}
for i:=0 to n-1 do begin
{Create title}
Labels[i] := TLabel.Create(Owner);
Labels[i].Parent := FScrollBox; //Self;
Labels[i].Caption := DataSource.DataSet.Fields[i].DisplayLabel;
Labels[i].Left := FLeft + (maxLabelLen +
maxTextLen + 10) * (i div RowCount);
Labels[i].Width := maxLabelLen;
Labels[i].Top := FTop + (i mod RowCount) * TextHeight + 5;
{Create editing object}
Editors[i] := TDBComboBox.Create(Owner);
Editors[i].Parent := FScrollBox; //Self;
Editors[i].Left := Labels[i].Left + Labels[i].Width;
Editors[i].Width := maxTextLen;
Editors[i].Top := FTop + (i mod RowCount) * TextHeight;
Editors[i].DataSource := DataSource;
Editors[i].DataField := DataSource.DataSet.Fields[i].FieldName;
Editors[i].OnKeyPress := AKeyPress;
Editors[i].OnKeyDown := AKeyDown;
end;
{Create Ok button}
OkButton := TButton.Create(Owner);
OkButton.Parent := FScrollBox;
OkButton.Left := Editors[n-1].Left;
OkButton.Top := Editors[n-1].Top + TextHeight;
OkButton.Caption := 'OK';
OKButton.OnClick := FClick;
end;
end;
destructor TDBPanel.Destroy;
begin
FreeEditors;
Inherited Destroy;
end;
function TDBPanel.Editor(Index: Integer): TDBComboBox;
begin
if Index< Length(Editors) then Result := Editors[Index]
else Result := nil;
end;
procedure TDBPanel.FreeEditors;
var
i,n: Integer;
begin
{Memory must be released in order! Must be done in reverse order of creation!
Especially when there is a parent-child relationship between components}
if OkButton< >nil then OkButton.Free;
if Editors< >nil then begin
n := Length(Editors);
for i:=0 to n-1 do Editors[i].free;
Editors := nil;
n := Length(Labels);
for i:=0 to n-1 do Labels[i].Free;
Labels := nil;
end;
if FScrollBox< >nil then begin
FScrollBox.Free;
FScrollBox := nil;
end;
end;
end.