Конференция "Основная" » Создание компонента
 
  • TForumHelp © (28.05.08 16:17) [0]
    Здравствуйте!

    Возможно ли динамически создать компонент, зная только его имя (например 'TEdit' или 'TButton'), и потом управлять им, как через OLE?

    чтобы получилось что-то типа:
    MyButton := CreateObjectFromClass('tbutton', Form1);
    MyButton.Parent := Form1;
    MyButton.Left := 150;
    MyButton.Top := 100;
    MyButton.Caption := 'Нажми меня!';
    MyButton.OnClick := MyButtonClick;

  • TForumHelp © (28.05.08 16:19) [1]
    Кстати, я подразумеваю создание не только стандартных компонентов, но и своих собственных!

    Заранее спасибо!
  • Reindeer Moss Eater © (28.05.08 16:28) [2]
    и потом управлять им, как через OLE?

    А почему не по infra red?
  • DimaBr © (28.05.08 16:32) [3]
    Для этого нужно зарегистрировать компонент

    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);

  • TForumHelp © (28.05.08 17:23) [4]
    а если я создам
    TButton

    , который имеет свойство
    Caption

    ?
    TControlClass(C).Create(self)

    не имеет этого свойства. Можно ли как-то по-другому это сделать (без регистрации итп)?
  • Reindeer Moss Eater © (28.05.08 17:27) [5]
    а если я создам TButton, который имеет свойство Caption?

    И чего? Создай.
  • {RASkov} © (28.05.08 18:05) [6]
    > [4] TForumHelp ©   (28.05.08 17:23)

    Наверное весж лучше расскажи задачу в целом..... иначе кажется что ты хочешь "не возможного" :)
  • Olegz77 © (28.05.08 21:23) [7]
    Запарненько это, если хочешь работать с любыми компонентами, созданными по имени класса, да еще и без приведения типа. Думаю, что это можно сделать, создав компонент, поддерживающий интерфейс IDispatch, но это все запа-а-арненько. Поищи статью Анатолия Тенцера про использование ActiveX компонента Microsoft Script Control. Там много есть, что пригодится
  • TForumHelp © (29.05.08 10:41) [8]
    Программа динамически подгружает 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

    ).
  • TForumHelp © (29.05.08 10:42) [9]

    > Возможно ли динамически создать компонент, зная только его
    > имя
    (например 'TEdit' или 'TButton'), и потом управлять
    > им, как через OLE?


    вот тут оговорился - извините.

    Имелось ввиду имя класса!
  • TForumHelp © (29.05.08 10:50) [10]
    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 я тоже пробовал создавать, но, как я уже говорил, я подразумеваю создание большого количества компонентов.
  • DimaBr © (29.05.08 11:09) [11]
    Начнём с начала и помедленнее.
    Вы хотите создавать динамически компоненты из некоего файла (базы).
    Для этого необходимо зарегистрировать данные классы и тогда они скомпилятся в вашу EXE-шку и и Вы сможете создавать те классы которые зарегистрированны.
    Иначе, допустим вы придумали механизм создания любого объекта без его компиляции. Первый же ворос, а как проинициализируются свойства в конструкторе если конструктор нескомпилирован ???
  • {RASkov} © (29.05.08 11:27) [12]
    > [8] TForumHelp ©   (29.05.08 10:41)
    > чтобы не добавлять модули Messages, Classes, Graphics, Controls,
    > Forms, Dialogs, StdCtrls, ..., которые значительно увеличат размер
    > библиотеки - нужно создавать их через "имя класса".

    Это не возможно! Код создаваемого компонента, пусть хоть через имя класса, должен быть в екзэ или длл...
    Так, что подключать все равно придеться модули с кодом компонентов, которые нужно потом в программе создавать...
  • TForumHelp © (29.05.08 11:32) [13]

    > должен быть в екзэ или длл...

    в exe он итак есть. через dll просто вызывается.
  • {RASkov} © (29.05.08 11:53) [14]
    Помоему тебе нужно в сторону БПЛ смотреть, иначе никак.... в длл и екзэ классы разные, хоть и одинаковые имена имеют...
  • DimaBr © (29.05.08 12:06) [15]
    > {RASkov}
    Он просто ещё не натыкался на эти грабли
  • TForumHelp © (30.05.08 07:33) [16]
    То есть я прошу чего-то нереального?... =( очень жаль.

    Придется работать с примером в [10]...
  • Palladin © (30.05.08 10:15) [17]

    > 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;

  • TForumHelp © (31.05.08 11:44) [18]

    > // не совсем понятно, на кой черт создавать на разные классы
    > разные массивы


    это делается для редактирования свойств в будующем и присваивания процедур.
  • TForumHelp © (31.05.08 12:46) [19]
    У меня еще один вопрос: как обрабатывать сообщения для созданного
    Controls[High(Controls)]

    , на подобие
    MouseEnter, MouseLeave, MouseDown, MouseUp

    итд?
  • Palladin © (02.06.08 11:05) [20]
    присваиванием обработчиков соответствующим событиям
  • icWasya © (02.06.08 14:33) [21]
    Изучать Classes.pas
    посмотри как сделан ReadComponent
  • TForumHelp © (02.06.08 16:24) [22]

    > присваиванием обработчиков соответствующим событиям

    а можно пожалуйста пример? :)

    и еще: можно ли какой-то функцией присвоить любому
    TComponent

    значение любому из его свойств, типа:

    function SetComponentProperty(var Component: TComponent; PropertyName, PropertyValue: String): Boolean;



    например:
    SetComponentProperty(MyControls[2], 'Caption', 'Push the button!');

  • {RASkov} © (02.06.08 16:38) [23]
    > [22] TForumHelp ©   (02.06.08 16:24)
    > а можно пожалуйста пример? :)

    Объект.СвойствоОбработчикСобытия:=СовместимыйМетод;

    > например: SetComponentProperty(MyControls[2], 'Caption',
    > 'Push the button!');

    SetPropValue
 
Конференция "Основная" » Создание компонента
Есть новые Нет новых   [134464   +62][b:0][p:0.003]