Советы по Delphi

         

Освобождение динамически создаваемых компонентов


...вы должны думать о Components (компонентах) как о List (списке), так что когда вы освобождаете элемент на конкретной позиции, она НЕ ОСТАЕТСЯ ПУСТОЙ, а немедленно заполняется (замещается) следующим пунктом, при этом свойство ComponentCount, на основе которого вы построили свой цикл (определили верхний диапазон), также уменьшается! Для защиты от такой ошибки, вы должны передвигаться к началу списка, опрашивая предыдущий по списку компонент:

    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]



Содержание раздела