Quick Tip: Dynamically Add Rows, Columns and Controls to Delphi’s TGridPanel


Delphi’s TGridPanel control is an ideal pick when you want to create grid-flow like user interface layout for your controls.

To place controls on a grid panel you specify the number of rows and columns (RowCollection and ColumnCollection properties) and simply drop a control on it. Unlike standard TPanel, when you drop a control on a GridPanel it will be placed in the next available empty cell in the grid. As you add more controls the grid will grow either by rows or columns being added automagically (or not, if the ExpandStyle poroperty is set to emFixedSize). What’s more you can even determine how each cell will be sized: will it have a fixed size, or a percentage of the grid size – so you can have controls nicely uniformly distributed in a grid.

That’s all great when you know the design at design-time – and you know what number of controls you want to be hosted by the grid panel.

What if you need to dynamically add controls to grid panel at run-time?

Say you do not know the number of rows or columns at design time, but you need to add controls to the grid panel dynamically where the number of rows/columns (/controls) changes. You’ll have to deal with RowCollection and ColumnCollection properties (to add or remove rows/columns). You’ll have to specify the SizeStyle for each cell and finally you have to somehow add a control to each cell.

So, without further ado, here’s how to add controls to GridPanel dynamically:

procedure TForm1.FormCreate(Sender: TObject);
begin
  GridPanel1.Caption := '';

  CreateButtonGrid(3,5);
end;

procedure TForm1.CreateButtonGrid(const rowCount, colCount : integer);
var
  i : integer;
  aButton: TButton;
begin
  GridPanel1.RowCollection.BeginUpdate;
  GridPanel1.ColumnCollection.BeginUpdate;

  for i := 0 to -1 + GridPanel1.ControlCount do
    GridPanel1.Controls[0].Free;

  //btw, cannot clear if there are controls, so first remove "old" controls above
  GridPanel1.RowCollection.Clear; 
  GridPanel1.ColumnCollection.Clear;

  for i := 1 to rowCount do
    with GridPanel1.RowCollection.Add do
    begin
      SizeStyle := ssPercent;
      Value := 100 / rowCount; //have cells evenly distributed
    end;

  for i := 1 to colCount do
    with GridPanel1.ColumnCollection.Add do
    begin
      SizeStyle := ssPercent;
      Value := 100 / colCount; //have cells evenly distributed
    end;

  for i := 0 to -1 + rowCount * colCount do
  begin
    aButton := TButton.Create(self);
    aButton.Parent := GridPanel1; //magic: place in the next empty cell
    aButton.Visible := true;
    aButton.Caption := 'Btn ' + IntToStr(i);
    aButton.Align := alClient;
    aButton.AlignWithMargins := true;
  end;

  GridPanel1.RowCollection.EndUpdate;
  GridPanel1.ColumnCollection.EndUpdate;
end;

So, on the form I have a GridPanel1 and the CreateButtonGrid(3,5) procedure will place 12 buttons in a 3 rows x 4 columns grid, each cell of the same size, buttons filling the cell with a pinch of margin. As you resize the form, buttons grow or shrink but are still evenly distributed in 3×4 grid. Nice!

And two extras:

Get Control at Row/Column

To get the control placed in a specified row / column you can use:

var
  aControl : TControl;
begin
  aControl := GridPanel1.ControlCollection.Controls[2,3]; //3rd row, 4th column
  if Assigned(aControl) AND (aControl IS TButton) then
    TButton(aControl).Caption := 'No hiding in 2,3';
end;

Get Row and Column where Control is

Now, you know a control is somewhere in the grid panel, and you need to know in what row / column:

var
  aControl : TControl;
  idx : integer;
  cRow, cColumn : integer;
begin
  //"pseudo" code (as aControl is nil)

  cRow := -1; cColumn := -1;
  idx := GridPanel1.ControlCollection.IndexOf(aControl);
  if idx > -1 then
  begin
    cRow := GridPanel1.ControlCollection[idx].Row;
    cColumn := GridPanel1.ControlCollection[idx].Column;
  end;
end;

Yes, the TGridPanel can be tricky to use, but when you find a use for it – you will not know how you lived without it 🙂

2 thoughts on “Quick Tip: Dynamically Add Rows, Columns and Controls to Delphi’s TGridPanel

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.