2009-02-11 2 views
12

Это, наверное, глупый вопрос, но мой мозг просто приготовлен достаточно, я думаю, что я собираюсь использовать один из своих «жизненных линий», чтобы увидеть, могу ли я получить некоторая помощь от моего переполнения друзей. ;)Удаление всех компонентов определенного класса на форме (Delphi)

Мне нужно удалить все вхождения определенного типа компонента в моей основной форме (некоторые из них находятся внутри панелей или таблиц, но все включено и принадлежит одной и той же форме). Вот что у меня сейчас:

for i := 0 to frmMain.ComponentCount - 1 do 
    begin 
    if frmMain.Components[i] is TMyClass then frmMain.Components[i].Destroy; 
    end;  

Проблема заключается в том (и я знал, что это было бы, прежде чем я скомпилировал его), что когда-то я уничтожу компонент, список компонентов повторных индексов форме, и я в конечном итоге выходит за границы.

Каков наилучший способ решить эту проблему? Я подумал о добавлении «найденных» компонентов в автономный массив, а затем пройти через это после этого цикла, чтобы удалить их, что, я думаю, будет работать ... но это лучший подход?

ТИА


UPDATE:

Вы, ребята, рок. Благодарю. :)

ответ

27

Вы почти правы. Ваш цикл должен выглядеть

for i := frmMain.ComponentCount - 1 downto 0 do 
begin 
    if frmMain.Components[i] is TMyClass then 
    frmMain.Components[i].Free; 
end; 

Таким образом, вызов функции «frmMain.ComponentCount» будет сделано в начале и не раз.

Вы также должны позвонить бесплатно, как указано выше, а не уничтожить - я не могу вспомнить, почему в данный момент. Bri

+4

Уничтожить виртуально. Если объект уже был уничтожен, он потерпит неудачу. Бесплатные проверки, чтобы проверить, есть ли у него действительная ссылка перед вызовом Destroy. Здесь, вероятно, не проблема, а хорошая практика в целом. –

+2

В этом случае можно просто вызвать Destroy.Из-за того, как VCL управляет этим списком, в этом списке вряд ли будет некорректная ссылка. Даже если бы это было так, Free не защищал бы вас, потому что он полагался на то, что экземпляр был ноль. –

+2

Обратите также внимание на то, что цикл переходит от высокого к нулю, чтобы гарантировать, что все элементы рассмотрены, в противном случае цикл может пропускать элементы рядом с удаленным. Важно не пропустить это. – mj2008

10

Начало сверху и работа назад.

а именно:

for i := frmMain.ComponentCount - 1 downto 0 do 
begin 
    if frmMain.Components[i] is TMyClass then frmMain.Components[i].Free; 
end; 

Вызов бесплатно вместо Destroy. Бесплатные звонки Уничтожьте после проверки действительной ссылки.

+1

Он должен также позвонить бесплатно и не уничтожить. Никогда не следует называть Destroy и всегда вызывать Free. –

1

же решение с While-цикле:

i := 0; 
while i < frmMain.ComponentCount do 
begin 
    if frmMain.Components[i] is TMyClass then 
    frmMain.Components[i].Free 
    else 
    inc(i); 
end; 
+0

это не сработает - (i) идет вверх и (frmMain.ComponentCount) сходит –

+1

Если вы посмотрите на второй взгляд, вы увидите, что я хочу придумать, если сработает компонентный счет. Если каждый компонент принадлежит классу TMyClass, я бы остался на нуле, и цикл while завершился бы, потому что 0 <0 является ложным – Vegar

2

Это не может произойти в вашем случае, но if frmMain.Components[i] is TMyClass проверка также будет возвращать верно для потомков классов TMyClass. Если вы действительно ищете удаление одного конкретного класса, вам может потребоваться дополнительная проверка ClassName.

-3

Если вам нужно проверить & уничтожить имени известного компонента Используйте

If YourComponent <> Nil Then 
    YourComponent.Free; 
+2

Это больше руды меньше, чем 'if YourComponent <> nil then , если YourComponent <> nil then YourComponent.Destroy; ' Двойной, если не **, что ** разумный, не так ли? :-) –

-2

для тонких Contrle в форме или панели могут использовать этот код

var 

i:Integer; 

begin 

for i := 0 to Panel1.ControlCount - 1 do 

    begin 

    if Panel1.Controls[i] is TEdit then 
     Tedit(Panel1.Controls[i]).text := ''; 

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