Най-често при програмиране в Delphi не е необходимо динамично да създавате компонент. Ако пуснете компонент върху формуляр, Delphi обработва създаването на компонента автоматично, когато формата е създадена. Тази статия ще обхване правилния начин за програмно създаване на компоненти по време на изпълнение.
Създаване на динамични компоненти
Има два начина за динамично създаване на компоненти. Един от начините е да направите форма (или някакъв друг TComponent) собственик на новия компонент. Това е често срещана практика при изграждане на композитни компоненти, при които визуален контейнер създава и притежава подкомпонентите. Това ще гарантира, че новосъздаденият компонент е унищожен, когато притежаващият компонент е унищожен.
За да създадете екземпляр (обект) на клас, извиквате неговия метод „Създаване“. Конструкторът Create е a клас метод, за разлика от почти всички други методи, които ще срещнете в програмирането на Delphi, които са обектни методи.
Например, TComponent декларира конструктора Create, както следва:
конструктор Създаване (AOwner: TComponent); виртуален;
Динамично създаване със собственици
Ето пример за динамично създаване, къде себе си е потомък на TComponent или TComponent (например екземпляр на TForm):
с TTimer. Създайте (Self) направи
започвам
Интервал: = 1000;
Активирано: = Грешно;
OnTimer: = MyTimerEventHandler;
край;
Динамично създаване с изрично обаждане към безплатно
Вторият начин за създаване на компонент е използването нула като собственик. Обърнете внимание, че ако направите това, вие също трябва да освободите изрично обекта, който създавате, веднага след като вече нямате нужда от него (или ще създадете изтичане на паметта). Ето пример за използване на nil като собственик:
с TTable. Създайте (нула) направете
опитвам
DataBaseName: = 'MyAlias';
Таблица: = 'MyTable';
Отворете;
Редактиране;
FieldByName ('Зает'). AsBoolean: = True;
Мнение;
накрая
Безплатно;
край;
Динамично създаване и препратки към обекти
Възможно е да се подобрят двата предишни примера чрез присвояване на резултата от Create call на променлива, локална на метода или принадлежаща към класа. Това често е желателно при позоваване на компонент трябва да се използват по-късно, или кога определяне на обхвата проблеми, потенциално причинени от блоковете „С“, трябва да се избягват. Ето кода за създаване на TTimer от по-горе, използвайки променлива на полето като препратка към създадения TTimer обект:
FTimer: = TTimer. Създаване (Self);
с FTimer do
започвам
Интервал: = 1000;
Активирано: = Грешно;
OnTimer: = MyInternalTimerEventHandler;
край;
В този пример "FTimer" е променлива на частно поле на формата или визуален контейнер (или каквото и да е "Self"). Когато имате достъп до променливата FTimer от методите от този клас, е много добра идея да проверите дали препратката е валидна, преди да я използвате. Това става с помощта на функцията Assigned на Delphi:
ако е назначен (FTimer), тогава FTimer. Активирано: = Вярно;
Динамично създаване и референции на обекти без собственици
Вариант на това е да създадете компонента без собственик, но да поддържате референцията за по-късно унищожаване. Строителният код за TTimer ще изглежда така:
FTimer: = TTimer. Създаване (нула);
с FTimer do
започвам
...
край;
И кодът за унищожаване (вероятно в деструктора на формата) би изглеждал така:
FTimer. Безплатно;
FTimer: = нула;
(*
Или използвайте процедурата FreeAndNil (FTimer), която освобождава референция на обект и заменя препратката с нула.
*)
Задаването на референтен обект на нула е критично при освобождаване на обекти. Обаждането към Безплатно първо проверява дали препратката към обекта е нула или не, и ако не е, извиква разрушителя на обекта Destroy.
Динамично създаване и локални препратки към обекти без собственици
Ето кода за създаване на TTable отгоре, използвайки локална променлива като препратка към създадения TTable обект:
localTable: = TTable. Създаване (нула);
опитвам
с местната таблица
започвам
DataBaseName: = 'MyAlias';
Таблица: = 'MyTable';
край;
...
// По-късно, ако искаме изрично да посочим обхвата:
localTable. Отворете;
localTable. Редактиране;
localTable. FieldByName ('Зает'). AsBoolean: = True;
localTable. Мнение;
накрая
localTable. Безплатно;
localTable: = нула;
край;
В горния пример "localTable" е a локална променлива деклариран по същия метод, съдържащ този код. Обърнете внимание, че след освобождаването на който и да е обект, като цяло е много добра идея да зададете референцията на нула.
Слово за предупреждение
ВАЖНО: Не смесвайте обаждане към Безплатно с предаване на валиден собственик на конструктора. Всички предишни техники ще работят и са валидни, но следващата трябва никога не се срещат в кода ви:
с TTable. Създайте (себе) направете
опитвам
...
накрая
Безплатно;
край;
Примерът с код по-горе въвежда ненужни хитове за производителност, повлиява леко на паметта и има потенциал да въведе трудно открити грешки. Разбери защо.
Забележка: Ако динамично създаденият компонент има собственик (посочен от параметъра AOwner на конструктора Create), тогава този собственик е отговорен за унищожаването на компонента. В противен случай трябва изрично да се обадите безплатно, когато вече не се нуждаете от компонента.
Член първоначално написан от Марк Милър
В Delphi беше създадена тестова програма, за да се създаде време за динамичното създаване на 1000 компонента с различен начален брой компоненти. Тестовата програма се появява в края на тази страница. Диаграмата показва набор от резултати от тестовата програма, сравнявайки времето, необходимо за създаване на компоненти както със собственици, така и без. Обърнете внимание, че това е само част от хита. Подобно забавяне на производителността може да се очаква при унищожаване на компоненти. Времето за динамично създаване на компоненти със собственици е 1200% до 107960% по-бавно от това за създаване компоненти без собственици, в зависимост от броя на компонентите във формата и компонента създаден.
Тестовата програма
Предупреждение: Тази тестова програма не проследява и безплатни компоненти, които са създадени без собственици. Като не проследявате и освобождавате тези компоненти, измерените времена за динамичния код за създаване по-точно отразяват реалното време за динамично създаване на компонент.
Изтеглете изходния код
Внимание!
Ако искате динамично да създадете компонент на Delphi и изрично да го освободите някъде по-късно, винаги предавайте нула като собственик. Ако не го направите, това може да доведе до ненужен риск, както и проблеми с работата и поддръжката на кода. Прочетете статията "Предупреждение за динамично инсталиране на компоненти на Delphi", за да научите повече ...