for i := Pred(ComponentCount) downto 0 do if (Components[i] is TButton) then TButton(Components[i]).Free; |
...у меня нет ответа на вопрос "Почему?", но у меня была та же проблема, когда при работе программы я разрушал дочерние MDI-окна. Вот как я решил эту проблему, и, надеюсь, это решение поможет и вам: { Удаляем текущее дочернее MDI-окно } ; WHILE MDIChildCount > 0 DO BEGIN ; MDIChildren[0].Close ; Application.ProcessMessages END В обработчике события OnClose дочернего MDI-окна установите параметр на "caFree", освобождающее окно при закрытии.
Проблема, которая была у меня, заключалась в том, что окно не освобождалось.
*МЫСЛЬ* Вот что я подумал: а может быть при освобождении компонентов пробовать давать команду Application.ProcessMessages? Я знаю, что при освобождении объектов инициируются несколько событий. И я догадываюсь о том, что сообщения должны быть обработаны объектом прежде, чем завершится его освобождение. Я также предполагаю, что причина вашей проблемы как раз в этом, поскольку, к примеру, следующий код вызывает бесконечный цикл: { Удаляем текущие дочерние MDI-окна } ; WHILE MDIChildCount > 0 DO MDIChildren[0].Close При добавлении Application.ProcessMessages код заработал, и цикл доходил до последнего элемента. Я не стал глубоко разбираться в том, как это работает внутри VCL, а был просто рад что это работает.
for i := 0 to ComponentCount-1 do if (Components[i] is TButton) then TButton(Components[i]).Free; |
Пока вы освобождаете ваши компоненты, список компонентов обновляется, но в вашем цикле это не учитывается. Это означает, что вы пытаетесь осободить компоненты, которых уже нет. Используйте:
for i := 0 to ComponentCount-1 do if (Components[0] is TButton) then TButton(Components[0]).Free; |
*** Индекс i изменяется до 0 ! ***
Это удалит все элементы. [001977]