2
votes

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?

4
If you have your edit boxes already on a form, make a TList<TEdit> generics collection, fill this collection at form creation with all analogous edit boxes and access them like PhoneEditList[RowIndex].Text. If I were you, I'd create them dynamically at runtime storing them in the TObjectList<TEdit> collection.TLama

4 Answers

2
votes

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.

1
votes

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.

1
votes

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.

0
votes
  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;
...