Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Создать контрол с заранее неизвестным классом [D7, WinXP]


Страницы:   1 2

den303_work ©   (2007-09-06 15:35:00) 

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

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

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


den303_work   (2007-09-07 10:39:00) [1]

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

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


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

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


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


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


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

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


Инс   (2007-09-06 17:58:00) [3]

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


Инс   (2007-09-06 17:49:00) [4]

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

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:44:00) [5]


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

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

Автору:
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.


homm   (2007-09-06 17:17:00) [6]

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

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


den303_work   (2007-09-06 17:15:00) [7]


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


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


tesseract   (2007-09-06 17:14:00) [8]


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


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


den303_work   (2007-09-06 17:11:00) [9]


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

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


clickmaker   (2007-09-06 17:09:00) [10]


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

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


Инс   (2007-09-06 17:06:00) [11]


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

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


Инс   (2007-09-06 17:04:00) [12]


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

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


clickmaker   (2007-09-06 17:04:00) [13]

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;


den303_work   (2007-09-06 17:03:00) [14]


> 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 вместо итемов, обе реализации не понравились.


homm   (2007-09-06 17:02:00) [15]

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


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


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

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


Dimaxx   (2007-09-06 16:49:00) [17]

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


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


den303_work   (2007-09-06 16:47:00) [18]


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

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


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


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

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


den303_work   (2007-09-06 16:35:00) [20]

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо