asg2012
asg2012

Reputation: 335

Calling TEdit objects based on DB query

I have a form with 7 TEdit having name EditPhone1, EditPhone2 and so on. In the same form I query a DB to get data to fill those TEdits. Of course I cannot know in advance how many results the query will return. How can I call the various TEdit objects when looping on the rowcount of the query?

Upvotes: 2

Views: 329

Answers (4)

NGLN
NGLN

Reputation: 43659

Use FindComponent to "convert" a component name to the component itself:

var
  Edit: TEdit;
  I: Integer;
begin
  DataSet.First;
  I := 1;
  while not DataSet.Eof do
  begin
    Edit := TEdit(FindComponent(Format('EditPhone%d', [I])));
    if Edit <> nil then
      Edit.Text := DataSet.FieldValues['PhoneNo'];
    DataSet.Next;
    Inc(I);
  end;

Now, this requires to hard-code the EditPhone%d string into the source which results in all kinds of maintainability issues. For example: consider renaming the edits.

Alternative 1:

To not rely on the component names, you could instead make use of TLama's idea and add all the edits to a list:

uses
  ... , Generics.Collections;

type
  TForm1 = class(TForm)
    EditPhone1: TEdit;
    ...
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FEdits: TList<TEdit>;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FEdits := TList<TEdit>.Create;
  FEdits.AddRange([EditPhone1, EditPhone2, EditPhone3, EditPhone4, EditPhone5,
    EditPhone6, EditPhone7]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FEdits.Free;
end;

procedure TForm1.ADOQuery1AfterOpen(DataSet: TDataSet);
var
  I: Integer;
begin
  DataSet.First;
  I := 0;
  while (not DataSet.Eof) and (I < FEdits.Count) do
  begin
    FEdits[I].Text := DataSet.FieldValues['PhoneNo'];
    DataSet.Next;
    Inc(I);
  end;
end;

This still requires some maintenance in case of adding edits in future.

Alternative 2:

You could also loop over all edits in the form to find the ones tagged to be added to the list, instead of adding them each explicitly:

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  FEdits := TList<TEdit>.Create;
  for I := 0 to ComponentCount - 1 do
    if (Components[I] is TEdit) and (TEdit(Components[I]).Tag = 1) then
      FEdits.Add(TEdit(Components[I]));
end;

But keeping those tags up to date is another burden.

Alternative 3:

I suggest you use a TDBGrid which is a data-component. Opening the linked dataset will automatically add all phone numbers to the grid. With some settings, the grid may kind of look like a couple of edits below each other.

Upvotes: 2

sybond
sybond

Reputation: 167

  1. Get query result (usually using .RowCount property of TDataset return)
  2. After getting the number of row, do iteration to make TEdit and set the text property

Here is sample of code:

...
For i:=0 to RowCount do
Begin
 A:=TEdit.Create(self);
 A.Parent:=AForm;
 A.Top:=i*14;
 A.Text:=ADataset.Field(i).AsString;
End;
...

Upvotes: 0

iMan Biglari
iMan Biglari

Reputation: 4776

I'd suggest using DBCtrlGrid. You place your controls for one row on it, and it repeats the controls for as many rows as your data set has.

Upvotes: 1

Andrey
Andrey

Reputation: 2729

You can, for example, use Tag property, to find needed component. Set all you TEdit's tag from 1 to 7 (or more), and find component by:

Var I: Integer;
    MyEdit : TEdit;

For I = 0 To Self.ComponentCount - 1 Do
 if (Self.Components[I] IS TEdit) AND (Self.Components[I] AS TEdit).Tag = YourTag
   MyEdit = (Self.Components[I] AS TEdit);

You can also dynamically create so many TEdits, you need, and assign Tag property on creation, and find it this code later in runtime.

Upvotes: 1

Related Questions