![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Создать контрол с заранее неизвестным классом [D7, WinXP]
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)
....