How can I refer to a control whose name is determined at runtime?

You can loop through the panel's Owner's Components array.

var
  i: Integer;
  TmpPanel: TPanel;
begin
  { This example loops through all of the components on the form, and toggles the
    Visible property of each panel to the value that is opposite of what it has (IOW,
    if it's True it's switched to False, if it's False it's switched to True). }
  for i := 0 to ComponentCount - 1 do                  
    if Components[i] is TPanel then                    
    begin
      TmpPanel := TPanel(Components[i]);
      TmpPanel.Visible := not TmpPanel.Visible;     // Toggles between true and false
    end;
end;

You can also use the FindComponent method, if you want a very specific type of component by name. For instance, if you have the 6 panels, and their names are Panel1, Panel2, and so forth:

var
  i: Integer;
  TmpPanel: TPanel;
begin
  for i := 1 to 6 do
  begin
    TmpPanel := FindComponent('Panel' + IntToStr(i)) as TPanel;
    if TmpPanel <> nil then      // We found it
      TmpPanel.Visible := not TmpPanel.Visible;
  end;
end;

This is a situation where you want to create the controls dynamically at runtime rather than at designtime. Trying to grapple with 6 different variables is just going to be a world of pain. And when you need the grid to be 3x4 rather than 2x3, you'll regret that decision even more.

So, start with a completely blank form. And add, in the code, a two dimensional array of panels:

private
  FPanels: array of array of TPanel;

Then, in the form's constructor, or an OnCreate event handler, you can initialise the array by calling a function like this:

procedure TMyForm.InitialisePanels(RowCount, ColCount: Integer);
var
  Row, Col: Integer;
  aLeft, aTop, aWidth, aHeight: Integer;
  Panel: TPanel;
begin
  SetLength(FPanels, RowCount, ColCount);
  aTop := 0;
  for Row := 0 to RowCount-1 do begin
    aLeft := 0;
    aHeight := (ClientHeight-aTop) div (RowCount-Row);
    for Col := 0 to ColCount-1 do begin
      Panel := TPanel.Create(Self);
      FPanels[Row, Col] := Panel;
      Panel.Parent := Self;
      aWidth := (ClientWidth-aLeft) div (ColCount-Col);
      Panel.SetBounds(aLeft, aTop, aWidth, aHeight);
      inc(aLeft, aWidth);
    end;
    inc(aTop, aHeight);
  end;
end;

And now you can refer to your panels using cartesian coordinates rather than a flat one dimensional array. Of course, you can easily enough declare a flat one dimensional array as well if you want.

The key idea is that when you are creating large numbers of control in a structured layout, you are best abandoning the designer and using code (loops and arrays).

Tags:

Delphi