Форум: "Основная";
Текущий архив: 2007.11.25;
Скачать: [xml.tar.bz2];
ВнизСоздать контрол с заранее неизвестным классом Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.038 c