问题
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.
回答1:
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 While
loops 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
来源:https://stackoverflow.com/questions/37589677/removing-controls-from-a-tgridpanel