TRequestFormDesc = record
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
tAssociatedForm :TForm; //Ассоциированная форма
end;
Как организовать работу с формами?
Делаю небольшую программу...
Существует список т.н. отчетов. За каждым из них закреплена своя соответствующая форма, которая должна открываться при клике на наименовании отчета в форме.
Сделал следующим образом.
Структура
Код:
Объявляю массив структур:
Код:
arrtRequestFormDesc :array of TRequestFormDesc;
Далее (ситуация с одним отчетом):
Код:
SetLength(arrtRequestFormDesc, nREQUESTS_COUNT);
arrtRequestFormDesc[0].nIndex := 0;
arrtRequestFormDesc[0].sDescription := 'Отчет 1';
arrtRequestFormDesc[0].sName := 'Report1';
arrtRequestFormDesc[0].tAssociatedForm := frmModuleDemandsReport1;
arrtRequestFormDesc[0].nIndex := 0;
arrtRequestFormDesc[0].sDescription := 'Отчет 1';
arrtRequestFormDesc[0].sName := 'Report1';
arrtRequestFormDesc[0].tAssociatedForm := frmModuleDemandsReport1;
Заполняю список с отчетами:
Код:
ListBox_ReportsList.Clear();
for i := 0 to Length(arrtRequestFormDesc) - 1 do begin
ListBox_ReportsList.Items.Add(arrtRequestFormDesc.sDescription);
end;
for i := 0 to Length(arrtRequestFormDesc) - 1 do begin
ListBox_ReportsList.Items.Add(arrtRequestFormDesc.sDescription);
end;
Теперь при щелчке на наименовании отчета:
Код:
arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tAssociatedForm.ShowModal();
Работает, как задумано. Но... предполагается, что форма с отчетом должна быть уже к этому времени создана:
Код:
Application.CreateForm(TfrmModuleDemandsReport1, frmModuleDemandsReport1);
Как мне организовать то же самое, но создавая форму в момент выбора пользователем отчета в списке?
Как я понимаю, необходимо учитывать в структуре при этом еще и класс данной формы - что то типа:
Код:
TRequestFormDesc = record
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
tAssociatedForm :TForm; //Ассоциированная форма
tCAssociatedForm :Что будет здесь? //Класс
end;
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
tAssociatedForm :TForm; //Ассоциированная форма
tCAssociatedForm :Что будет здесь? //Класс
end;
А затем:
Код:
Application.CreateForm(arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tCAssociatedForm, arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tAssociatedForm);
arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tAssociatedForm.ShowModal();
arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tAssociatedForm.ShowModal();
Возможно сделать такое?
Сведу все к одному:
При создании формы приложение принимает класс формы и экземпляр:
Код:
Application.CreateForm(
TfrmReqForm, frmReqForm
);
TfrmReqForm, frmReqForm
);
Можно ли как-то получить ссылку на тип, имея экземпляр?
т.е.
Код:
Application.CreateForm(
{как получить?}, frmReqForm
);
{как получить?}, frmReqForm
);
ссылку на класс? TObject.ClassType
Объявление структуры:
Код:
TFormClass = class of TForm;
TRequestFormDesc = record
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
[COLOR=Red]//tAssociatedForm :TForm; // Может это поле не нужно?[/COLOR]
tCAssociatedForm : TFormClass; // Класс формы отчета
end;
TRequestFormDesc = record
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
[COLOR=Red]//tAssociatedForm :TForm; // Может это поле не нужно?[/COLOR]
tCAssociatedForm : TFormClass; // Класс формы отчета
end;
При заполнении структуры:
Код:
//...
SetLength(arrtRequestFormDesc, nREQUESTS_COUNT);
arrtRequestFormDesc[0].nIndex := 0;
arrtRequestFormDesc[0].sDescription := 'Отчет 1';
arrtRequestFormDesc[0].sName := 'Report1';
arrtRequestFormDesc[0].tCAssociatedForm := [COLOR=Red]T[/COLOR]frmModuleDemandsReport1;
//...
SetLength(arrtRequestFormDesc, nREQUESTS_COUNT);
arrtRequestFormDesc[0].nIndex := 0;
arrtRequestFormDesc[0].sDescription := 'Отчет 1';
arrtRequestFormDesc[0].sName := 'Report1';
arrtRequestFormDesc[0].tCAssociatedForm := [COLOR=Red]T[/COLOR]frmModuleDemandsReport1;
//...
Ну и вызов формы:
Код:
var ReportForm: TForm;
begin
ReportForm:=arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tCAssociatedForm.Create(Application);
ReportForm.ShowModal;
ReportForm.Free;
end;
begin
ReportForm:=arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tCAssociatedForm.Create(Application);
ReportForm.ShowModal;
ReportForm.Free;
end;
До этого была родительская форма и наследники.
Уже упростил задачу:
Структура:
Код:
tCAssociatedForm : TForm;
Заполнение:
Код:
arrtRequestFormDesc[0].tCAssociatedForm := frmTest;
Здесь frmTest обычная форма от TForm.
Выполняю:
Код:
var ReportForm: TForm;
begin
ReportForm:=arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tCAssociatedForm.Create(Application);
ReportForm.ShowModal;
ReportForm.Free;
begin
ReportForm:=arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].tCAssociatedForm.Create(Application);
ReportForm.ShowModal;
ReportForm.Free;
Результат: Access Violation если форма еще не создана.
Если в свойствах проекта ее создавать при запуске приложения - никаких проблем:(
Что я делаю не так?
Цитата: dominator
Существует список т.н. отчетов. За каждым из них закреплена своя соответствующая форма, которая должна открываться при клике на наименовании отчета в форме.
В подобных случаях не раз советовал удалить переменную формы (первый, второй, третий), чтобы медвежья услуга IDE не мешала думать, как правильно создавать и уничтожать формы динамически.
Цитата: dominator
Структура
Код:
TRequestFormDesc = record
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
tAssociatedForm :TForm; //Ассоциированная форма
end;
nIndex :Integer; //Индекс формы в списке форм
sDescription :String; //Описание формы
sName :String; //Идентификатор
tAssociatedForm :TForm; //Ассоциированная форма
end;
nIndex - лишний, если не служит чем-то вроде ID. Индексом формы является индекс записи в массиве, описанном ниже. tAssociatedForm правильней описать AssociatedFormClass: TFormClass. Получаем:
Код:
TRequestFormDesc = record
Name: string;
Description: string;
AssociatedFormClass: TFormClass;
end;
Name: string;
Description: string;
AssociatedFormClass: TFormClass;
end;
Цитата: dominator
Объявляю массив структур
Логичней и проще описать перечислимый тип типов отчётов (без каламбура никак), и инициализацию массива перенести на этап компиляции:
Код:
type
TRequestFormKind = (rfdFirst, rfdSecond, rfdThird, rfdSomething);
const
RequestFormDesc: array [TRequestFormKind] of TRequestFormDesc = (
(Name: 'Первый отчёт'; Description: 'Подумайте о первом отчёте'; AssociatedFormClass: TFirstRequestForm),
(Name: 'Второй отчёт'; Description: 'Подумайте о втором отчёте'; AssociatedFormClass: TSecondRequestForm),
(Name: 'Третий отчёт'; Description: 'Сообразим на троих?'; AssociatedFormClass: TThirdRequestForm),
(Name: 'ХЗ какой отчёт'; Description: 'Тут придётся напрячься'; AssociatedFormClass: TSomethingRequestForm)
);
TRequestFormKind = (rfdFirst, rfdSecond, rfdThird, rfdSomething);
const
RequestFormDesc: array [TRequestFormKind] of TRequestFormDesc = (
(Name: 'Первый отчёт'; Description: 'Подумайте о первом отчёте'; AssociatedFormClass: TFirstRequestForm),
(Name: 'Второй отчёт'; Description: 'Подумайте о втором отчёте'; AssociatedFormClass: TSecondRequestForm),
(Name: 'Третий отчёт'; Description: 'Сообразим на троих?'; AssociatedFormClass: TThirdRequestForm),
(Name: 'ХЗ какой отчёт'; Description: 'Тут придётся напрячься'; AssociatedFormClass: TSomethingRequestForm)
);
Обращение идёт примерно так:
Код:
begin
with RequestFormDesc[TRequestFormKind(ListBox_ReportsList.ItemIndex)].Create(Application) do
try
ShowModal;
finally
Free;
end;
end;
with RequestFormDesc[TRequestFormKind(ListBox_ReportsList.ItemIndex)].Create(Application) do
try
ShowModal;
finally
Free;
end;
end;
И ещё совет: следуйте правилам именования Borland - откажитесь от венгерской нотации (в данном случае - "псевдовенгерской"). Простой код понятен и без костылей.
Очень благодарен за помощь. Спасибо всем откликнувшимся!
Хочу держать информацию о классе формы в бд. Каким образом это реализовать? Делаю так:
1. Таблица. Упрощенно -
id, Title, Name, Associated_form и прочее.
2. Читаю нужную строку. Причем в Associated_form записано значение, к примеру:
TfrmReport1
3. Загоняю полученное значение в AssociatedFormClass следующим образом: TFormClass(VarToStr(мое значение...))
Компилируется без проблем. На этапе исполнения:
Код:
oRepForm:=arrtRequestFormDesc[ListBox_ReportsList.ItemIndex].AssociatedFormClass.Create(Application);
oRepForm.ShowModal;
oRepForm.Free;
oRepForm.ShowModal;
oRepForm.Free;
получаю Access Violation.
Конечно же, если просто присвоить: AssociatedFormClass := TfrmReport1 все отработает нормально.
Как-то вообще такое можно сделать? В чем моя ошибка?