Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.55 MB
Время: 0.05 c
15-1191929132
Nucer
2007-10-09 15:25
2007.11.25
Ever more


15-1192999930
SerJaNT
2007-10-22 00:52
2007.11.25
ACDSee 3.0


11-1178440374
Dy1
2007-05-06 12:32
2007.11.25
оптимизатор JPEG


15-1192354956
Stanislav
2007-10-14 13:42
2007.11.25
Сканер памяти (типа ArtMoney)


15-1193056466
Антон Шестаков
2007-10-22 16:34
2007.11.25
Создание справки





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский