-
Здравствуйте! Возможно ли динамически создать компонент, зная только его имя (например 'TEdit' или 'TButton'), и потом управлять им, как через OLE? чтобы получилось что-то типа: MyButton := CreateObjectFromClass('tbutton', Form1);
MyButton.Parent := Form1;
MyButton.Left := 150;
MyButton.Top := 100;
MyButton.Caption := 'Нажми меня!';
MyButton.OnClick := MyButtonClick;
-
Кстати, я подразумеваю создание не только стандартных компонентов, но и своих собственных!
Заранее спасибо!
-
и потом управлять им, как через OLE?
А почему не по infra red?
-
Для этого нужно зарегистрировать компонент procedure TForm1.Button1Click(Sender: TObject);
var C: TPersistentClass;
begin
C := FindClass('TPanel');
if Assigned(C) then begin
TControlClass(C).Create(self).Parent := form1 ;
end;
end;
initialization
RegisterClass(TPanel);
-
а если я создам TButton , который имеет свойство Caption ? TControlClass(C).Create(self) не имеет этого свойства. Можно ли как-то по-другому это сделать (без регистрации итп)?
-
а если я создам TButton, который имеет свойство Caption?
И чего? Создай.
-
> [4] TForumHelp © (28.05.08 17:23)
Наверное весж лучше расскажи задачу в целом..... иначе кажется что ты хочешь "не возможного" :)
-
Запарненько это, если хочешь работать с любыми компонентами, созданными по имени класса, да еще и без приведения типа. Думаю, что это можно сделать, создав компонент, поддерживающий интерфейс IDispatch, но это все запа-а-арненько. Поищи статью Анатолия Тенцера про использование ActiveX компонента Microsoft Script Control. Там много есть, что пригодится
-
Программа динамически подгружает Dll, через который осуществляется "отрисовка" компонентов на компоненте, переданом плагину. procedure DrawComponents(var Parent: TWinControl); чтобы не добавлять модули Messages, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ... , которые значительно увеличат размер библиотеки - нужно создавать их через " имя класса". Я пытался уже сделать таким образом:
var
S: String;
function ComponentToString(Component: TComponent): String;
function StringToComponent(Component: String): TMemoryStream;
implementation
S имеет значение:
object MyButton: TButton
Left = 5
Top = 5
Width = 75
Height = 25
Caption = 'Button'
TabOrder = 2
end
теперь ф-и:
function ComponentToString(Component: TComponent): String;
var
MS: TMemoryStream;
SS: TStringStream;
S: String;
begin
MS := TMemoryStream.Create;
MS.WriteComponent(Component);
MS.Seek(0, soFromBeginning);
SS := TStringStream.Create(S);
ObjectBinaryToText(MS, SS);
Result := SS.DataString;
end;
function StringToComponent(Component: String): TMemoryStream;
var
MS: TMemoryStream;
SS: TStringStream;
S: String;
begin
MS := TMemoryStream.Create;
S := Component;
SS := TStringStream.Create(S);
ObjectTextToBinary(SS, MS);
MS.SaveToFile('component.dat'); MS.Free;
MS := TMemoryStream.Create;
MS.LoadFromFile('component.dat');
DeleteFile('component.dat');
Result := MS;
end;
теперь использование:
StringToComponent(S).ReadComponent(Button1);
Каким-то образом нужно создать компонент, который "получит" наши параметры (на примере Button1 ).
-
> Возможно ли динамически создать компонент, зная только его > имя (например 'TEdit' или 'TButton'), и потом управлять > им, как через OLE?
вот тут оговорился - извините.
Имелось ввиду имя класса!
-
var
Buttons: array of TButton;
CButtons: Integer;
Edits: array of TEdit;
CEdits: Integer;
ClassName: String;
ClassData: String;
на примере: ClassName = 'TButton';, а ClassData = 'object MyButton: TButton Left = 5 Top = 5 Width = 75 Height = 25 Caption = 'Button' TabOrder = 2 end'; обрабатываем: procedure DrawComponent(var Parent: TWinControl; ClassName, ClassData: String);
begin
If LowerCase(ClassName) = 'tbutton' then begin
Inc(CButtons);
SetLength(Buttons, CButtons+1);
Buttons[CButtons] := TButton.Create(Parent);
Buttons[CButtons].Parent := Parent;
StringToComponent(ClassData).ReadComponent(Buttons[CButtons]);
end else
If LowerCase(ClassName) = 'tedit' then begin
Inc(CEdits);
SetLength(Edits, CEdits+1);
Edits[CEdits] := TEdits.Create(Parent);
Edits[CEdits].Parent := Parent;
StringToComponent(ClassData).ReadComponent(Edits[CEdits]);
end else
If LowerCase(ClassName) = 't...' then begin
end else
begin
end;
end; Если использовать таким образом, то придется добавлять огромное кольчество массивов и переменных, так как классов для создания я подразумеваю очень много. Обработка тоже будет "огромной". Через WinApi я тоже пробовал создавать, но, как я уже говорил, я подразумеваю создание большого количества компонентов.
-
Начнём с начала и помедленнее. Вы хотите создавать динамически компоненты из некоего файла (базы). Для этого необходимо зарегистрировать данные классы и тогда они скомпилятся в вашу EXE-шку и и Вы сможете создавать те классы которые зарегистрированны. Иначе, допустим вы придумали механизм создания любого объекта без его компиляции. Первый же ворос, а как проинициализируются свойства в конструкторе если конструктор нескомпилирован ???
-
> [8] TForumHelp © (29.05.08 10:41) > чтобы не добавлять модули Messages, Classes, Graphics, Controls, > Forms, Dialogs, StdCtrls, ..., которые значительно увеличат размер > библиотеки - нужно создавать их через "имя класса".
Это не возможно! Код создаваемого компонента, пусть хоть через имя класса, должен быть в екзэ или длл... Так, что подключать все равно придеться модули с кодом компонентов, которые нужно потом в программе создавать...
-
> должен быть в екзэ или длл...
в exe он итак есть. через dll просто вызывается.
-
Помоему тебе нужно в сторону БПЛ смотреть, иначе никак.... в длл и екзэ классы разные, хоть и одинаковые имена имеют...
-
> {RASkov} Он просто ещё не натыкался на эти грабли
-
То есть я прошу чего-то нереального?... =( очень жаль.
Придется работать с примером в [10]...
-
> TForumHelp © (30.05.08 07:33) [16]
во первых откажись от dll и уйди на bpl, от dll тебе никакого проку нет, а вот RTTI будет уже общее, это раз. два. так как у тебя будет bpl. ты спокойным образом сможешь передавать в функцию не имя класса контрола, а ссылку на класс контрола. и делается это так: procedure DrawComponent(var Parent: TWinControl; CtrlClass:TWinControlClass;Const ClassData: String);
begin
SetLength(Controls, Length(Controls)+1);
Controls[High(Controls)] := CtrlClass.Create(Parent);
Controls[High(Controls)].Parent := Parent;
StringToComponent(ClassData).ReadComponent(Controls[High(Controls)]);
end;
-
> // не совсем понятно, на кой черт создавать на разные классы > разные массивы
это делается для редактирования свойств в будующем и присваивания процедур.
-
У меня еще один вопрос: как обрабатывать сообщения для созданного Controls[High(Controls)] , на подобие MouseEnter, MouseLeave, MouseDown, MouseUp итд?
-
присваиванием обработчиков соответствующим событиям
-
Изучать Classes.pas посмотри как сделан ReadComponent
-
> присваиванием обработчиков соответствующим событиям
а можно пожалуйста пример? :) и еще: можно ли какой-то функцией присвоить любому TComponent значение любому из его свойств, типа: function SetComponentProperty(var Component: TComponent; PropertyName, PropertyValue: String): Boolean; например: SetComponentProperty(MyControls[2], 'Caption', 'Push the button!');
-
> [22] TForumHelp © (02.06.08 16:24) > а можно пожалуйста пример? :)
Объект.СвойствоОбработчикСобытия:=СовместимыйМетод;
> например: SetComponentProperty(MyControls[2], 'Caption', > 'Push the button!');
SetPropValue
|