Динамическое создание компонентов Delphi (во время выполнения)

Чаще всего при программировании на Delphi вам не нужно динамически создавать компонент. Если вы удаляете компонент в форме, Delphi автоматически обрабатывает создание компонента при создании формы. В этой статье будет рассмотрен правильный способ программного создания компонентов во время выполнения.

Создание динамического компонента

Существует два способа динамического создания компонентов. Одним из способов является создание формы (или некоторого другого TComponent) владельцем нового компонента. Это обычная практика при создании составных компонентов, когда визуальный контейнер создает и владеет подкомпонентами. Это гарантирует, что вновь созданный компонент будет уничтожен при уничтожении его владельца.

Чтобы создать экземпляр (объект) класса, вы вызываете его метод «Создать». Конструктор Create является метод классаВ отличие от практически всех других методов, с которыми вы столкнетесь в программировании на Delphi, которые являются объектными методами.

Например, TComponent объявляет конструктор Create следующим образом:

instagram viewer

конструктор Create (AOwner: TComponent); виртуальный;

Динамическое создание с владельцами
Вот пример динамического создания, где само является потомком TComponent или TComponent (например, экземпляром TForm):

с TTimer. Создать (Self) сделать
начать
Интервал: = 1000;
Включено: = Ложь;
OnTimer: = MyTimerEventHandler;
конец;

Динамическое создание с явным призывом к свободе
Второй способ создать компонент - это использовать ноль как владелец. Обратите внимание, что если вы сделаете это, вы также должны явно освободить созданный вами объект, как только он вам больше не понадобится (или вы создадите утечка памяти). Вот пример использования nil в качестве владельца:

с TTable. Создать (ноль) сделать
пытаться
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
Открыто;
Редактировать;
FieldByName ('Busy'). AsBoolean: = True;
Почта;
наконец
Свободно;
конец;

Динамическое создание и ссылки на объекты
Можно улучшить два предыдущих примера, назначив результат вызова Create переменной, локальной для метода или принадлежащей классу. Это часто желательно, когда ссылки на компонент нужно использовать позже, или когда обзорное следует избегать проблем, которые могут быть вызваны блоками «С». Вот код создания TTimer сверху, использующий переменную поля в качестве ссылки на экземплярный объект TTimer:

FTimer: = TTimer. Создать (Self);
с FTimer сделать
начать
Интервал: = 1000;
Включено: = Ложь;
OnTimer: = MyInternalTimerEventHandler;
конец;

В этом примере «FTimer» является частной переменной поля формы или визуального контейнера (или любого другого «Self»). При обращении к переменной FTimer из методов этого класса, очень хорошая идея проверить, является ли ссылка действительной перед ее использованием. Это делается с помощью функции Delphi Assigned:

если назначено (FTimer), то FTimer. Включено: = Истина;

Динамическое создание и ссылки на объекты без владельцев
Вариантом этого является создание компонента без владельца, но сохранение ссылки для последующего уничтожения. Код конструкции для TTimer будет выглядеть так:

FTimer: = TTimer. Создать (ноль);
с FTimer сделать
начать
...
конец;

И код уничтожения (предположительно в деструкторе формы) будет выглядеть примерно так:

FTimer. Свободно;
FTimer: = ноль;
(*
Или используйте процедуру FreeAndNil (FTimer), которая освобождает ссылку на объект и заменяет ссылку на nil.
*)

Установка ссылки на объект на ноль имеет решающее значение при освобождении объектов. Вызов Free сначала проверяет, является ли ссылка на объект нулевой или нет, а если нет, то вызывает деструктор объекта Destroy.

Динамическое создание и ссылки на локальные объекты без владельцев

Вот код создания TTable сверху, использующий локальную переменную как ссылку на экземплярный объект TTable:

localTable: = TTable. Создать (ноль);
пытаться
с localTable сделать
начать
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
конец;
...
// Позже, если мы хотим явно указать область действия:
localTable. Открыто;
localTable. Редактировать;
localTable. FieldByName ('Busy'). AsBoolean: = True;
localTable. Почта;
наконец
localTable. Свободно;
localTable: = ноль;
конец;

В приведенном выше примере «localTable» является локальная переменная объявлено в том же методе, содержащем этот код. Обратите внимание, что после освобождения любого объекта, в общем, очень хорошая идея установить ссылку на ноль.

Слово предупреждения

ВАЖНО: не смешивайте вызов Free с передачей действительного владельца конструктору. Все предыдущие методы будут работать и действительны, но следующие должны никогда не встречается в вашем коде:

с TTable. Создать (самостоятельно) сделать
пытаться
...
наконец
Свободно;
конец;

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

Примечание. Если динамически созданный компонент имеет владельца (определяется параметром AOwner конструктора Create), то этот владелец отвечает за уничтожение компонента. В противном случае вы должны явно вызвать Free, когда вам больше не нужен компонент.

Статья изначально написана Марк Миллер

В Delphi была создана тестовая программа для определения времени динамического создания 1000 компонентов с различным начальным числом компонентов. Тестовая программа появится внизу этой страницы. Диаграмма показывает набор результатов тестовой программы, сравнивая время, необходимое для создания компонентов как с владельцами, так и без. Обратите внимание, что это только часть попадания. Аналогичная задержка производительности может ожидаться при уничтожении компонентов. Время динамического создания компонентов с владельцами на 1200–107960% медленнее, чем на создание компоненты без владельцев, в зависимости от количества компонентов в форме и компонента создано.

Тестовая программа

Предупреждение: эта тестовая программа не отслеживает и освобождает компоненты, созданные без владельцев. Не отслеживая и не освобождая эти компоненты, время, измеренное для кода динамического создания, более точно отражает реальное время динамического создания компонента.

Скачать исходный код

Предупреждение!

Если вы хотите динамически создать компонент Delphi и явно освободить его через некоторое время, всегда передавайте nil в качестве владельца. Невыполнение этого требования может привести к ненужному риску, а также к проблемам с производительностью и обслуживанием кода. Прочитайте статью «Предупреждение о динамическом создании компонентов Delphi», чтобы узнать больше ...

instagram story viewer