Решение для динамически создаваемых компонентов
Предупреждение: Если вы просто хотите во время выполнения
приложения создавать компоненты необходимого вам типа, ознакомьтесь с файлом
delphi\doc\VB2Delph.wri и следуйте его рекомендациям, лучшего способа изучения
этой темы пока не существует. Данный совет повествует об использовании в Delphi
RTTI.
Во-первых, в вашем приложении необходимо зарегистрировать все классы,
экземпляры которых вы собираетесь в каком-то месте кода создавать. Сделать это
можно с помощью функций RegisterClass(), RegisterClasses() и
RegisterClassAlias().
Пример:
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterClasses([TButton, TEdit, TMemo, TLabel]);
end;
|
Это может навести вас на мысль об ограничениях, но Delphi строгий язык. Если
вы хотите истинно динамическое создание объектов в слаботипизированной среде
позднего связывания, используйте динамический язык типа Smalltalk. У меня есть
подозрение, что Delphi использует этот механизм регистрации для регистрации всех
компонентов в DCL при его запуске, позволяя этим самым создавать любой компонент
во время разработки.
Создание компонентов. Используйте функцию FindClass() для получения ссылки на
класс компонента, который вы хотите создать, и вызывайте его метод Create.
Легко, не правда ли? В примере у меня имеется приведение типа SomeComponent к
TControl, после чего я уже могу установить свойство parent (я могу делать это,
поскольку я знаю, что все зарегистрированные мною классы являются потомками
TControl). Для того, чтобы визуальный компонент появился на форме, вам
необходимо установить свойство parent.
Пример:
procedure TForm1.CreateClick(Sender: TObject);
begin
SomeComponent:= TComponentClass(FindClass(ClassName.Text)).Create(Self);
(SomeComponent as TControl).Parent := Self;
end;
|
Теперь, когда вы имеете созданный компонент, как установить его свойства без
использования самого большого блока case во вселенной? Очень просто: для
получения информации о свойстве из структуры run-time type information (RTTI)
используется функция GetPropInfo(), после чего для установления значений
используется набор функций SetXXXXProp(). (Примечание: эти функции не
задокументированы в файлах помощи Delphi. OO-программисты, как я понимаю,
пользуются примерами из чужого кода и не изобретают свой велосипед.) У каждой
функции SetXXXXProp() имеется функция-сателлит GetXXXXProp(), позволяющая узнать
значения свойств объекта.
Пример:
procedure TForm1.SetPropertyClick(Sender: TObject);
var
PropType: PTypeInfo;
PropInfo: PPropInfo;
begin
PropInfo := GetPropInfo(SomeComponent.ClassInfo, PropertyName.Text);
PropType := PropInfo^.PropType;
case PropType^.Kind of
tkInteger:
SetOrdProp(SomeComponent, PropInfo,
StrToInt(PropertyValue.Text));
tkChar:
SetOrdProp(SomeComponent, PropInfo, Ord(PropertyValue.Text[1]));
tkEnumeration:
SetOrdProp(SomeComponent, PropInfo, GetEnumValue(PropType,
PropertyValue.Text));
tkFloat:
SetFloatProp(SomeComponent, PropInfo,
StrToFloat(PropertyValue.Text));
tkString:
SetStrProp(SomeComponent, PropInfo, PropertyValue.Text);
end;
end;
|
Вы также можете установить значения свойств Set, Class и Method, но это будет
немного сложнее. Немного позже я объясню как это можно сделать.
Это все. Вы проведете время с большой пользой, изучая исходный код VCL, и
удивляясь, когда вы все там увидите собственными глазами.
Это прекрасный способ, но он имеет потенциал для массового злоупотребления.
Необходимо понимание других путей достижения этой цели и выбор соответствующей
техники при создании своих проектов в Delphi.
|