2016-06-02 5 views
3

Я использую TGridPanel для управления несколькими панелями. Я создаю панели и добавить их к GridPanel с помощью кода, как следующее:Удаление элементов управления из TGridPanel

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; 

Вы заметите, что каждая панель имеет другое значение тега.

Я хотел бы удалить панель из GridPanel на основе значения в свойстве тега панели. Я пробовал следующий код:

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; 

Это хорошо работает, если панель является последней панелью в коллекции. Если я попытаюсь удалить панель с тегом = 1 или tag = 2, я получаю ошибку вне диапазона. Нажатие «continue» в отладчике оставляет место, где была удалена панель, поэтому удаляет панель.

Что бы я хотел видеть, скажем, панель 2 удалена и последующие панели перетасовываются на одно место, чтобы не осталось пробелов.

Как это сделать?

Я использую Delphi 10.1 Berlin, если это имеет значение.

+1

Reverse свой цикл, 'GridPanel2.ControlCollection.Count -1 downto 0' –

+0

спасибо, @DalijaPrasnikar. Я пропустил разрыв из петли. Поскольку каждое значение тега уникально, только одна панель будет удалена. Это исправляет ошибку вне диапазона, но не перетасовку остальных оставшихся панелей. Еще раз спасибо, –

+0

Я откат вашего редактирования, потому что с ним вы удалили всю причину возникновения вопроса. С добавлением 'break' проблема, которую вы описываете, не возникает, и поэтому вопрос не имеет значения для будущих читателей здесь. Неправильно редактировать код и удалять всю причину публикации, особенно после того, как кто-то ответил на эту ошибку в сообщении. Вы не только тратите время на этого человека, но полностью отрицаете ответ, что может привести к тому, что этот человек потеряет репутацию из-за голосов по этому теперь неправильному ответу. –

ответ

2

Как всегда при удалении элемента из списка или коллекции вам необходимо принять меры предосторожности при изменении счетчика. Счетчик циклов вычисляется в начале цикла. Теперь, если вы удалите элемент из списка, вы столкнетесь с несуществующим индексом, когда цикл for продолжится до конца.

Вы можете избежать этого разными способами, f.ex. выйдя из цикла, как только вы нашли и удалили элемент.

freeandnil(pnl); 
    break; 

Другой способ, чтобы запустить цикл назад

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

Или вы можете использовать Repeat Until или While петли, которые проверяет условие продолжения на каждом шагу цикла.

Чтобы обновить панель сетки после удаления пунктов называют один или оба

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

Однако, он чувствует себя довольно сложно, чтобы получить заказ прямо

+0

Спасибо, это был недостаток перерыва, который вызывал ошибку за пределами границ. Честно говоря, я не могу поверить, что пропустил это. Я дам UpdateControlsXXX() попробовать и посмотреть, смогу ли я заставить их работать. Еще раз спасибо, –

+0

Ну, UpdateControlsXXX() работает. Я использую ноль в качестве параметра и использую порядок, в котором вы их вставляете. Еще раз спасибо @TomBrunberg –

Смежные вопросы