3

I'm using TGridPanel to manage a number of panels. I create the panels and add them to the GridPanel using code like the following:

var
  pnl: TPanel;
begin
  pnl := TPanel.Create(GridPanel2);
  pnl.Caption := 'Panel One';
  pnl.Tag := 1;
  pnl.Parent := GridPanel2;
  pnl.Name := 'pnlOne';

  GridPanel2.ControlCollection.AddControl(pnl);


  pnl := TPanel.Create(GridPanel2);
  pnl.Caption := 'Panel Two';
  pnl.Tag := 2;
  pnl.Parent := GridPanel2;
  pnl.Name := 'pnlTwo';

  GridPanel2.ControlCollection.AddControl(pnl);


  pnl := TPanel.Create(GridPanel2);
  pnl.Caption := 'Panel Three';
  pnl.Tag := 3;
  pnl.Parent := GridPanel2;
  pnl.Name := 'pnlThree';

  GridPanel2.ControlCollection.AddControl(pnl);
end;

You will notice that each panel has a different tag value.

I'd like to remove a panel from the GridPanel based on the value in the panel's tag property. I have tried the following code:

var
  ii: integer ;
  pnl: TPanel;
begin
  for ii := 0 to GridPanel2.ControlCollection.Count -1 do begin
    if GridPanel2.ControlCollection[ii].Control.Tag = 1 then begin
      pnl := GridPanel2.ControlCollection[ii].Control as TPanel;

      GridPanel2.ControlCollection.RemoveControl(pnl);

      freeandnil(pnl);
    end;
  end;
  gridpanel2.Refresh();
end;

This works well providing the panel is the last panel in the collection. If I try to remove the panel with tag = 1 or tag = 2 I get an out of range error. Clicking "continue" in the debugger leaves a space where the removed panel was, so does remove the panel.

What I'd like to see is, say panel 2 removed and subsequent panels shuffled down one place to leave no gaps.

How do I do this?

I'm using Delphi 10.1 Berlin if that matters.

Ken White
  • 123,280
  • 14
  • 225
  • 444
Michael Vincent
  • 1,620
  • 1
  • 20
  • 46
  • 1
    Reverse your loop, `GridPanel2.ControlCollection.Count -1 downto 0` – Dalija Prasnikar Jun 02 '16 at 11:39
  • Thank you, @DalijaPrasnikar. I had missed a Break out of the loop. As each tag value is unique only one panel will be deleted. That fixes the out of range error, but not the shuffling along of the remaining panels. Thanks again, – Michael Vincent Jun 02 '16 at 11:49
  • I rolled back your edit, because with it you've removed the entire reason for the question to exist. With the `break` added, the problem you describe does not occur, and therefore the question has no value to future readers here. It's inappropriate to edit the code and remove the entire reason for posting,especially after someone answers based on that error being in the post. You not only waste the time of that person,but you negate the answer entirely, which can result in that individual losing reputation due to votes on that now-incorrect answer. – Ken White Jun 02 '16 at 12:59
  • @KenWhite thank you. – Michael Vincent Jun 02 '16 at 13:30

1 Answers1

2

As always when deleting an item from a list or collection you need to take precaution when the count changes. A for loop count is determined at the beginning of the loop. Now, if you delete an item from the list you will hit a non-existing index when the for loop continues to the end.

You can avoid this in many ways, f.ex. by breaking out of the loop, once you have found and deleted the item.

  freeandnil(pnl);
  break;

Another way, is to run the for loop backwards

  for ii := GridPanel2.ControlCollection.Count -1 downto 0 do begin

Or you can use Repeat Until or Whileloops which checks the condition to continue on every turn of the loop.

To update the grid panel after deleting items call either or both of

  gridpanel2.UpdateControlsRow();
  gridPanel2.UpdateControlsColumn();

However, it feels quite tricky to get the order right

Tom Brunberg
  • 20,312
  • 8
  • 37
  • 54
  • Thank you, it was the lack of a break that was causing the out of bounds error. I can't believe I missed it, to be honest. I'll give the UpdateControlsXXX() a try and see if I can get them to work. Thanks again, – Michael Vincent Jun 02 '16 at 11:54
  • Well, the UpdateControlsXXX() work. I use zero as a parameter and used the order you have them in. Thanks again, @TomBrunberg – Michael Vincent Jun 02 '16 at 12:02