Accessing Dynamically Created Components At Runtime

I have created some tabsheets at runtime, and created ListBoxes to go with them:

      // Does the Tab Exist?
      TabFound := False;
      if Length(TabName) > 0 then
        begin
          for j := 0 to PageControl1.PageCount - 1 do
            begin
              if PageControl1.Pages[j].Caption = TabName then
                begin
                  TabFound := True;
                  Break;
                end;
            end;
          if not TabFound then
            begin
              // Add Tab
              with TTabSheet.Create(PageControl1) do
                begin
                  PageControl := PageControl1;
                  TabVisible := True;
                  Caption := TabName;
                  // Add the ListBox
                  with TListBox.Create(PageControl1.Pages[PageControl1.PageCount -1]) do
                    begin
                      Parent := PageControl1.Pages[PageControl1.PageCount -1];
                      Top := 24;
                      Left := 16;
                      Width := 641;
                      Height := 297;
                      Name := StripSpaces(TabName)+'ListBox';
                      OnMouseUp := ProgramListBoxMouseUp;
                    end;
                end;
             end;
        end;

I then need to access the individual list boxes to add items to them.   If I use FindComponent or iterate through the component list it doesn't find any listboxes at all, not even the one created at design time:

      // Load into the List Box
      if TabName = '' then
        ProgramListBox.Items.AddObject(DisplayText, p)
      else
        begin
          ListBoxName := StripSpaces(TabName)+'ListBox';
          // Test code to see if listboxes being found
          for j := 0 to ComponentCount-1 do
            begin
              Temp := Components[i];
              if Temp is TListBox then
                ShowMessage(TListBox(Temp).Name);  // This never fires, therefore no list boxes?
            end;
          // This should have found it and done the job!!
          ListBox := TListBox(FindComponent(ListBoxName));
          if ListBox <> NIL then
            ListBox.Items.AddObject(DisplayText, p)
          else
            ShowMessage('Not Found');
        end;
    end;

Obviously I am missing something damn silly - anyone got any ideas?
LVL 3
chrisbrayAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

chrisbrayAuthor Commented:
Typo in there - i instead of j:

     // Load into the List Box
      if TabName = '' then
        ProgramListBox.Items.AddObject(DisplayText, p)
      else
        begin
          ListBoxName := StripSpaces(TabName)+'ListBox';
          // Test code to see if listboxes being found
          for j := 0 to ComponentCount-1 do
            begin
              Temp := Components[j];
              if Temp is TListBox then
                ShowMessage(TListBox(Temp).Name);  // This never fires, therefore no list boxes?
            end;
          // This should have found it and done the job!!
          ListBox := TListBox(FindComponent(ListBoxName));
          if ListBox <> NIL then
            ListBox.Items.AddObject(DisplayText, p)
          else
            ShowMessage('Not Found');
        end;
    end;

Still doesn't work, though!!

Chris Bray.
esoftbgCommented:
Try this:

unit Unit1_Q_21485950;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    PageControl1: TPageControl;
    Panel1: TPanel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
      ListBox:  TListBox;
      function  TabSheet_Exists(SName: string): Boolean;
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  I:      Integer;
begin
  with PageControl1 do
  begin
    for I := 0 to 9 do
    begin
      with TTabSheet.Create(Self) do
      begin
        PageControl := PageControl1;
        TabVisible := (PageIndex mod 2 = 0);
        Caption := 'PageIndex: ' + IntToStr(PageIndex) + '  TabIndex: ' + IntToStr(TabIndex);
        Name := 'TabSheet' + IntToStr(I);
      end;
    end;
    ListBox := TListBox.Create(Self);
    ListBox.Parent := PageControl1.Pages[0];
    ListBox.Height := 400;
    ListBox.Width := 600;
  end;
end;

function  TForm1.TabSheet_Exists(SName: string): Boolean;
var
  I:      Integer;
begin
  Result := False;
  for I := 0 to ComponentCount-1 do
  begin
    if (Components[I] is TTabSheet) then
    begin
      if ((Components[I] as TTabSheet).Name=SName) then
      begin
        Result := True;
        Break;
      end;  
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I:      Integer;
  S:      string;
begin
  ListBox.Clear;
  for I := 0 to 9 do
  begin
    S := 'TabSheet' + IntToStr(I);
    if TabSheet_Exists(S) then
      ListBox.Items.Add(S);
  end;
end;

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

end.
esoftbgCommented:
download above example from:
page:        http://www.geocities.com/esoftbg/
  link:        Q_21485950.zip        Accessing Dynamically Created Components At Runtime
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

chrisbrayAuthor Commented:
I am very sorry to say that your response is no help whatsoever...  my code can already do all that and more!

The problem is after I create listboxes on the internal dynamically created pages.  The reason this is a problem is that despite giving them a name which can be confirmed as given using a simple piece of test code FindComponent does not find them, and iterating through the list of components does not report ANY TListBoxes - not even the one that is created at designtime on the initial tabsheet.

Whilst I am sure that this is something stupid I am doing (or not doing) I would be very grateful to find out what it is!

To look at your example, I might need to create a listbox on TabSheet3, call it ListBox3,  and add something to it.  I need to be able to do ListBox3.Items.Add('ThisString') or whatever... but without pre-coding it.

Chris Bray.
chrisbrayAuthor Commented:
Here is another example that perhaps shows the problem more effectively.  The following procedure is assigned to all the Listboxes as part of the creation routine in the original code:

procedure TMainForm.ProgramListBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  APoint: TPoint;
  Index: Integer;
begin
  if Button = mbRight then
    begin
      ShowMessage(TListBox(Sender).Name);  // This reports the correct name of all the Listboxes

      if FindComponent(TListBox(Sender).Name) <> NIL then // Returns NIL on all dynamic listboxes,
        ShowMessage('Found It!')                                         // even though sender name is correct...
      else
        ShowMessage('Couldn''t Find It ...');
    end;
end;

As the comments show, the correct ListBox names is returned if you right click on it.  However, if you call FindComponent using the correct name it returns NIL!  

Chris Bray.
Slick812Commented:
hello  chrisbray. . I think that the FindComponent and conponentcount are for components that are OWNED by that conponent, you seem to be searching for the list boxes with the Form's FindComponent, maybe if you used this code in the button click above it might work better, I beleive?


 if PageControl1.ActivePage.FindComponent(TListBox(Sender).Name) <> NIL then
        ShowMessage('Found It!');

not able to run this now, so it is untested code

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Slick812Commented:
sorry. . . I should have said -
in the  
      procedure TMainForm.ProgramListBoxMouseUp  
 code above
chrisbrayAuthor Commented:
Hi Slick812,

Thanks for that - said it was probably something stupid, didn't I?  Must be going daft in my old age :-)

Chris Bray.
esoftbgCommented:
procedure TMainForm.ProgramListBoxMouseUp(Sender: TObject;
                                          Button: TMouseButton;
                                          Shift: TShiftState;
                                          X, Y: Integer);
begin
  if Button = mbRight then
  begin
    ShowMessage(TListBox(Sender).Name);  // This reports the correct name of all the Listboxes

    if (Assigned(TListBox(Sender))) then
      ShowMessage('Found It!')
    else
      ShowMessage('Couldn''t Find It ...');
  end;
end;
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.