Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.11.25;
Скачать: CL | DM;

Вниз

Создать контрол с заранее неизвестным классом   Найти похожие ветки 

 
den303_work ©   (2007-09-06 15:35) [0]

Доброго времени суток!

Проблема такая:
В XML записаны некоторые объекты (контролы) и их свойства. Я генерирую форму в run-time из этого файла. Заранее класс контрола неизвестен. Как мне объявить класс контрола на этапе проетирования, притом что нужен доступ к специфическим свойствам (к примеру, Caption для TLabel)?

Вопрос вдогонку :o) :
Какое объявление лучше использовать для хранения списка контролов и подчинённых им свойств (у каждого контрола, опять же, свой набор)?


 
Ega23 ©   (2007-09-06 15:37) [1]


> Как мне объявить класс контрола на этапе проетирования,
> притом что нужен доступ к специфическим свойствам (к примеру,
>  Caption для TLabel)?


переформулируй, а то вообще не въехал...


 
Dib@zol ©   (2007-09-06 15:41) [2]

Ну типа читает прога ХМЛ. Видит: object "name1" class "BUTTON" ну или как-то так. Дык вот, этого класса окно ему и надо создать.
Правильно ли работает телепатор [Y/N]?


 
Инс ©   (2007-09-06 15:41) [3]

см. RegisterClasses/FindClass


 
den303_work ©   (2007-09-06 15:43) [4]


> Ega23 ©   (06.09.07 15:37) [1]

Уххх... Сумбурно объяснил, сорри. Короче, надо написать процедуру создания контрола
var
 obj:TControl;
 s:string;  //<-здесь хранится тип контрола, вытянутый из xml. В данном случае TLabel.
begin
 obj:=TControl.Create;
 //Надо типа того: obj:=s.Create;
...

Даже не представляю, куда копать


 
den303_work ©   (2007-09-06 15:45) [5]


> Dib@zol ©   (06.09.07 15:41) [2]

Абсолютно верно! [Y/N] :o)


 
den303_work ©   (2007-09-06 16:07) [6]


var
 obj:TControl;
 s:string; //<-тип контрола("TLabel")
begin
 obj:=TControl(s);
 obj:=TControl.Create(self);
 obj.Parent:=Form1;
 (obj as TLabel).Caption:="test"; //<-на этом месте вылетает, даже несмотря на то, что я объявляю as TLabel

Ну а нужно опять же типа (obj as s).Caption:="test";

ЗЫ: Caption здесь просто для примера, на самом деле свойства для каждого контрола тож из xml идут и все валидные

ЗЫ2:
> Инс ©   (06.09.07 15:41) [3]

Тож не катит (либо я не понял), т.к. в xml могут быть абсолютно любые классы контролов. Не объявлять же все...


 
Dib@zol ©   (2007-09-06 16:13) [7]

> в xml могут быть абсолютно любые классы контролов. Не объявлять же все...

у, батенька, это увы не прокатит. Тут либо окно вручную создавать и мессаги ему слать, либо никак... Каждый компонент из ВЦЛ заточен только под свой набор свойств. Сложно даже представить себе, какие глюки пойдут, если скажем ВЦЛьной кнопке проставили напр класс "msctls_toolbar32".


 
Игорь Шевченко ©   (2007-09-06 16:16) [8]


>  Как мне объявить класс контрола на этапе проетирования,
>  притом что нужен доступ к специфическим свойствам (к примеру,
>  Caption для TLabel)?


Использовать RTTI, доступ к свойствам сделать через GetxxxxProp|SetxxxProp (uses TypInfo)


 
den303_work ©   (2007-09-06 16:17) [9]


> Dib@zol ©   (06.09.07 16:13) [7]

Не, ну понятно, что классы опять же будут валидными. Но, блин.... А, ладно! Объявлю, какие есть, пусть так работает.

Тогда см. второй вопрос :o)


 
Dib@zol ©   (2007-09-06 16:19) [10]

> Тогда см. второй вопрос :o)

У ИНИ-файла отличная структура, никогда не подволила =)


 
Инс ©   (2007-09-06 16:22) [11]

А стандартная сериализация/десериализация не подходит?


 
homm ©   (2007-09-06 16:25) [12]

> Какое объявление лучше использовать для хранения списка
> контролов и подчинённых им свойств (у каждого контрола,
> опять же, свой набор)?

А кто запрещает в dfm хранить?


 
den303_work ©   (2007-09-06 16:27) [13]


> Игорь Шевченко ©   (06.09.07 16:16) [8]

ОК, сенкс, попробую.


> Dib@zol ©   (06.09.07 16:19) [10]

Не в файле, а в переменной :o)
Думал использовать Array of array of string и TList с TStringList вместо итемов, обе реализации не понравились.


> Инс ©   (06.09.07 16:22) [11]

Ммммм.... А что это? [бьётся головой о стол :o( ]


 
Инс ©   (2007-09-06 16:30) [14]


> Ммммм.... А что это? [бьётся головой о стол :o( ]

См. TStream.WriteComponent, TStream.ReadComponent, классы TReader, TWriter.


 
den303_work ©   (2007-09-06 16:35) [15]

Я имею ввиду, хранить структуру в переменной(ных).
Что-нибудь типа двухмерного динамического массива:
(TLabel,caption)
(TLabel,name)
...
(TButton,caption)
(TButton,top)
....


 
Инс ©   (2007-09-06 16:36) [16]


> den303_work ©   (06.09.07 16:35) [15]

А TStringStream не подходит? Или TMemoryStream?


 
den303_work ©   (2007-09-06 16:47) [17]


> Инс ©   (06.09.07 16:36) [16]

Это всё одномерные списки. А мне нужен двухмерный, типа таблицы. Каждая запись - контрол, каждый столбец - параметр. Но т.к. у всех контролов параметры разные, сл-но.... Крыша едет :o(


 
Dimaxx ©   (2007-09-06 16:49) [18]

var
obj: TControl;
s: string; //<-тип контрола("TLabel")
begin
if s="TLabel" then
 begin
  obj:=TLabel.Create(Form1);
  obj.Parent:=Form1;
  obj.Caption:="test";
 end;
end;


А что-то типа такого подойдет?


 
Инс ©   (2007-09-06 16:50) [19]


> А мне нужен двухмерный, типа
> таблицы.

ТЗ так звучит? Яже говорю, храните не в своем придуманном формате, а в стандартном, который поддерживают инструменты стандартной сериализации. Или будем изобретать велосипед с квадратными колесами?


 
homm ©   (2007-09-06 17:02) [20]

Что значит хранить параметры? Разве сами компоненты не хранят свои параметры?


 
den303_work ©   (2007-09-06 17:03) [21]


> Dimaxx ©   (06.09.07 16:49) [18]

Безусловно подойдёт, но есть одна маааленькая проблема: заранее неизвестно ни число, ни тип используемых контролов. См. с начала ветки.
Хотя я так и начал делать... пока не нашёл другого решения....


> Инс ©   (06.09.07 16:50) [19]

В ТЗ не входят пути решения. Но, понимаете, я не могу использовать одномерные списки, ибо получается следующее:
TLabel   | name | caption | left | top
TImage  | left   | top       | image
TButton | action
....

Думал использовать Array of array of string и TList с TStringList вместо итемов, обе реализации не понравились.


 
clickmaker ©   (2007-09-06 17:04) [22]

type TControlClass = class of TControl;
type TClassArray = array[0..7] of TControlClass;

const
 ClassArray: TClassArray = (
                    TButton, TRadioButton, TCheckBox,
                    TGroupBox, TComboBox, TListBox,
                    TEdit, TStaticText);

...

FClassList := TStringList.Create;
FClassList.Add("TButton");
FClassList.Add("TRadioButton");
...

var
 idx: integer;
 Cl: TControlClass;
 Ctl: TControl;

 idx := FClassList.IndexOf("TEdit");  // пример, имя можно читать из файла
 if (idx > -1) then begin

   Cl := TControlClass((ClassArray[idx]));
   Ctl := Cl.Create(Self);
   Ctl.Parent := Self;
   Ctl.SetBounds(0, 0, 100, 21);
   Ctl.Visible := true;
   if IsPublishedProp(Cl, "Text") then
     SetStrProp(Ctl, "Text", "MyEdit");
 end;


 
Инс ©   (2007-09-06 17:04) [23]


> den303_work ©   (06.09.07 17:03) [21]

Ясно, вы даже не смотрели то, что я порекомендовал в [14]. Если будет не лень, приду домой и набросаю вам пример.


 
Инс ©   (2007-09-06 17:06) [24]


> clickmaker ©   (06.09.07 17:04) [22]

Щас опять скажет, что его это не устраивает, бо компоненты на форме могут быть любого класса.


 
clickmaker ©   (2007-09-06 17:09) [25]


>  [24] Инс ©   (06.09.07 17:06)

в массив можно забить все возможные классы (разумеется, они должны быть зарегистрированы - а иначе вообще ничего не поможет)


 
den303_work ©   (2007-09-06 17:11) [26]


> homm ©   (06.09.07 17:02) [20]

Безусловно хранят. Объясню:
Я парсю XML-файл, где находится описание типов используемых контролов и их свойства (для каждого контрола свой список свойств).
При парсинге эти данные нужно сохранять в какую-то переменную (массив, список, запись...).
После чего контролы эти создаются на форме.
В любой момент времени работы программы юзеру может понадобиться изменить любое свойство любого контрола.
Было бы просто выводить свойства для правки прямо от контрола, но минус в том, что свойства даны далеко не все, да ещё и видоизменённые некоторые (чтобы пользователю было понятней).
Посему мне и нужно держать этот список в памяти.
Какую лучше структуру использовать для этого?


 
tesseract ©   (2007-09-06 17:14) [27]


> Какую лучше структуру использовать для этого?


Дерево конечно.


 
den303_work ©   (2007-09-06 17:15) [28]


> clickmaker ©   (06.09.07 17:09) [25]
>Инс ©   (06.09.07 17:06) [24]


ОК, сенкс, завтра буду реализовывать - отпишусь.
Не обижайтесь, просто не мастер ещё, не сталкивался...


 
homm ©   (2007-09-06 17:17) [29]

> [26] den303_work ©   (06.09.07 17:11)
> После чего контролы эти создаются на форме

Объясняю еше раз. Используй dfm для хранения и загрузки компонентов, все что тебе нужно уже реализовано в самой VCL.


 
Инс ©   (2007-09-06 17:44) [30]


> в массив можно забить все возможные классы (разумеется,
> они должны быть зарегистрированы - а иначе вообще ничего
> не поможет)

Достаточно зарегистрировать класс самой формы.

Автору:
1. Создаем новый проект и новую Available Form
2. На вторую форму кидаем любые компоненты
3. На первую - одну кнопку и пишем такой код:
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

uses Unit2;

var
 Stream: TMemoryStream;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 frm: TForm;
begin
 frm:=TFormClass(FindClass("TForm2")).CreateNew(nil);
 Stream.Position:=0;
 Stream.ReadComponent(frm);
 frm.ShowModal;
 frm.Free;
end;

initialization
 // Регистрируем класс формы
 RegisterClasses([TForm2]);
 // Просто создаем Stream и заполняем его
 Stream:=TMemoryStream.Create;
 Form2:=TForm2.Create(nil);
 try
   Stream.WriteComponent(Form2);
 finally
   Form2.Free;
 end;

finalization
 Stream.Free;

end.


 
Инс ©   (2007-09-06 17:49) [31]

Если класс формы известен на этапе компиляции, то можно вообще без регистрации:

implementation

uses Unit2;

var
 Stream: TMemoryStream;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 frm: TForm;
begin
 frm:=TForm2.CreateNew(nil);
 Stream.Position:=0;
 Stream.ReadComponent(frm);
 frm.ShowModal;
 frm.Free;
end;

initialization
 // Просто создаем Stream и заполняем его
 Stream:=TMemoryStream.Create;
 Form2:=TForm2.Create(nil);
 try
   Stream.WriteComponent(Form2);
 finally
   Form2.Free;
 end;

end.


 
Инс ©   (2007-09-06 17:58) [32]

А если класс данной формы не объявлен в проекте, то вы вообще никак не сделаете это без регистрации всех возможных классов контролов. А даже если сделаете, то обратится к компонентам формы как к свойствам не сможете (типа же нету).


 
Игорь Шевченко ©   (2007-09-06 18:04) [33]


> Я парсю XML-файл, где находится описание типов используемых
> контролов и их свойства (для каждого контрола свой список
> свойств).
> При парсинге эти данные нужно сохранять в какую-то переменную
> (массив, список, запись...).
> После чего контролы эти создаются на форме.
> В любой момент времени работы программы юзеру может понадобиться
> изменить любое свойство любого контрола.
> Было бы просто выводить свойства для правки прямо от контрола,
>  но минус в том, что свойства даны далеко не все, да ещё
> и видоизменённые некоторые (чтобы пользователю было понятней).
>
> Посему мне и нужно держать этот список в памяти.
> Какую лучше структуру использовать для этого?


Стандартный метод TReader.ReadComponent (RTFS classes.pas) парсит dfm-файл (текстовый, например), в котором находится описание типов используемых контролов и их свойства (для каждого контрола свой список
свойств).

Найди десять отличий.


 
den303_work ©   (2007-09-07 10:39) [34]

Огромные спасибы всем, реализация понятна.

Отдельный TNX clickmaker ©   (06.09.07 17:04) [22] и Инс ©   (06.09.07 17:44) [30] - именно то, что нужно.


> Игорь Шевченко ©   (06.09.07 18:04) [33]

Понял, тож реализацию посмотрел, спасибо.



Страницы: 1 вся ветка

Текущий архив: 2007.11.25;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.018 c
2-1193738764
apic
2007-10-30 13:06
2007.11.25
delphi 2007


15-1192731111
Чайник
2007-10-18 22:11
2007.11.25
Это троян? Или что?


15-1192777802
vajo
2007-10-19 11:10
2007.11.25
Игра ма-джонг


15-1193077784
NAlex
2007-10-22 22:29
2007.11.25
TOpenDialog + куда девается память?


2-1193848611
harisma
2007-10-31 19:36
2007.11.25
Позиционирование на запись в ComboBox