|
Вопрос # 4 994/ вопрос открыт / |
|
Приветствую, уважаемые эксперты!
Формы - открытие.
В программе вспомогательных форм много и открытие их должно происходить примерно так, через одну процедуру, которая вызывается в главной форме
Procedure OpenForm(sNameForm: String);
(sNameForm as Tform).Create(Application)
....
Или что-то в этом роде.
Подскажите, как правильно и возможно ли так?
Спасибо
 |
Вопрос задал: vladrvv (статус: Посетитель)
Вопрос отправлен: 2 февраля 2011, 06:36
Состояние вопроса: открыт, ответов: 0.
|
Мини-форум вопроса
Всего сообщений: 19; последнее сообщение — 7 февраля 2011, 09:01; участников в обсуждении: 5.
|
bugmenot (статус: 3-ий класс), 2 февраля 2011, 10:24 [#1]:
А с чего ты вообще взял что так можно делать? В частности, приводить _строку_ к _классу_. Читай внимательно топик "Class references" и далее. Потом разбери след. пример:
procedure TForm12.FormClick(Sender: TObject);
type
TFormClass = class of TForm;
var
FormClass: TFormClass;
begin
RegisterClass(TPersistentClass(Self.ClassType));
FormClass := TFormClass(FindClass(Self.ClassName));
FormClass.Create(Application).Show;
end;
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
min@y™ (статус: Доктор наук), 2 февраля 2011, 12:58 [#2]:
Настоятельно не рекомендую управлять объектом по имени.
А классов форм действительно много? "Много" - это сколько? Скорее всего, решить эту проблему можно иначе и намного изящнее. Требуются подробности.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
vladrvv (статус: Посетитель), 2 февраля 2011, 20:42 [#3]:
Речь идет о MDI формах
В начале было так
Procedure TFormGL.btnGilecClick(Sender: TObject);
var
i,nK: integer;
LysL:Boolean;
begin
if (ActiveMDIChild = Nil) then begin
TFormGILEC.Create(Application);
end
else begin
for i:= 0 to MdiChildCount - 1 do begin
if MDIChildren[i].Caption ='Жильцы' then begin
LysL:=True;
nK:=i;
end;
end;
if LysL then
MDIChildren[nK].Show
else begin
TFormGILEC.Create(Application);
end;
end;
end
Потом оказалось, что форм много, они могут открываться из разных мест( меню, бар, из другого окна) и захотелось обобщить код.Написать одну процедуру , через которую производилось создание окна или его активация.
изменил код так
procedure TFormGL.btnGilecClick(Sender: TObject);
var
fGilec:TForm;
sGLString:string;
begin
fGilec:=FormGILEC;
sGLString:='Жильцы';
MyFormOpen(fGilec,sGLString);
end;
procedure tFormGL.MyFormOpen(sNameform:TForm;sText:String);
var
i,nK: integer;
LysL:Boolean;
fGilec:TForm;
begin
LysL:=False;
fGilec:=sNameform;
if (FormGL.ActiveMDIChild = Nil) then begin
(fGilec as TForm).Create(Application);
end
else begin
for i:= 0 to FormGL.MdiChildCount - 1 do begin
if FormGL.MDIChildren[i].Caption =sText then
LysL:=True;
nK:=i;
end;
end;
if LysL then
FormGL.MDIChildren[nK].Show
else begin
(fGilec as TForm).Create(Application);
end;
end;
Дописал функцию MyFormOpen
Программа компилируется без замечаний, но при попытке запуска данной процедуры - выдает сообщение
Access violation at ..
|
|
min@y™ (статус: Доктор наук), 3 февраля 2011, 08:41 [#4]:
Расскажу, как делаю я. Если у меня в проекте есть больше одной формы, показ и закрытие (если форма немодальная) каждой их этих форм я оформляю функциями внутри модуля каждой формы. Щас приведу примерчик.
Модальная:
// Форма
TReportForm = class(TForm)
// <--- вся начинка тут
end;
var
ReportForm: TReportForm; // Глобальная переменная
procedure ShowReport(AReport: TSelfControlReport);
implementation
{$R *.dfm}
procedure ShowReport(AReport: TSelfControlReport);
begin
if not Assigned(ReportForm)
then ReportForm:= TReportForm.Create(Application);
try
ReportForm.FReport:= AReport;
ReportForm.UpdateInfo();
ReportForm.ShowModal();
finally
FreeAndNil(ReportForm);
end;
end;
Заметь, для разных форм удобно использовать разные функции их показа, в них можно передать нужные параметры (здесь передаётся AReport: TSelfControlReport).
Ещё пример модальной формы:
// Создание нового разъёма устройства
function GetNewPlugInfo(var Info: TPlugInfo): Boolean;
var
Item: TPlugTypeItem;
begin
if not Assigned(NewPlugForm)
then NewPlugForm:= TNewPlugForm.Create(Application);
try
NewPlugForm.ShortNameEdit.Text:= Info.ShortName;
NewPlugForm.LongNameEdit.Text:= Info.LongName;
NewPlugForm.RefreshPlugTypeComboBox(nil);
Result:= NewPlugForm.ShowModal() = mrOk;
if Result
then with NewPlugForm do
begin
Info.ShortName:= NewPlugForm.ShortNameEdit.Text;
Info.LongName:= NewPlugForm.LongNameEdit.Text;
if PlugTypesComboBox.ItemIndex <> -1
then begin
Item:= TPlugTypeItem(PlugTypesComboBox.Items.Objects[PlugTypesComboBox.ItemIndex]);
if Assigned(Item)
then begin
Info.PinsCount:= Item.PinsCount;
Info.PlugTypeName:= Item.PlugTypeName;
Info.PlugType:= Item.PlugType;
end;
end;
end; // with
finally
FreeAndNil(NewPlugForm);
end;
end;
// Редактирование существующего разъёма устройства
function EditPlug(APlug: TDevPlug): Boolean;
var
Item: TPlugTypeItem;
begin
// Изменение разъёма
if not Assigned(NewPlugForm)
then NewPlugForm:= TNewPlugForm.Create(Application);
try
NewPlugForm.ShortNameEdit.Text:= APlug.ShortName;
NewPlugForm.LongNameEdit.Text:= APlug.LongName;
NewPlugForm.RefreshPlugTypeComboBox(PlugTypesHolder.ItemsByCRC32[APlug.PlugTypeNameCRC32]);
Result:= NewPlugForm.ShowModal() = mrOk;
if Result
then with NewPlugForm do
begin
APlug.ShortName:= NewPlugForm.ShortNameEdit.Text;
APlug.LongName:= NewPlugForm.LongNameEdit.Text;
if PlugTypesComboBox.ItemIndex <> -1
then begin
Item:= TPlugTypeItem(PlugTypesComboBox.Items.Objects[PlugTypesComboBox.ItemIndex]);
if Assigned(Item)
then begin
APlug.PlugTypeNameCRC32:= Item.CRC32;
APlug.PlugType:= Item.PlugType;
end
else begin
APlug.PlugTypeNameCRC32:= 0;
APlug.PlugType:= ptUnknown;
end;
end;
end; // with
finally
FreeAndNil(NewPlugForm);
end;
end;
Эти 2 функции создают и потом убивают одну и ту же форму, но с разными действиями. Функции возвращают True, если юзер нажал кнопку "ОК" и введённые им данные оказались верными, False - если юзер нажал кнопку "Отмена".
Немодальная (MDIChild):
TBuffersForm = class(TForm)
// <--- Начинка здесь
end;
var
BuffersForm: TBuffersForm;
procedure ShowBuffersForm;
procedure CloseBuffersForm;
implementation
{$R *.dfm}
// Показ формы
procedure ShowBuffersForm;
begin
if not Assigned(BuffersForm)
then BuffersForm:= TBuffersForm.Create(Application);
with BuffersForm do
begin
UpdateData();
Show();
end;
end;
// Закрытие
procedure CloseBuffersForm;
begin
BuffersForm.Close();
end;
// Финализация - обязательно.
procedure TBuffersForm.FormDestroy(Sender: TObject);
begin
// Всякая нужная ботва
BuffersForm:= nil; // <--- Обнуление глобального указателя
end;
procedure TBuffersForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action:= caFree;
end;
Если тебе нужно, чтобы в один момент вроемени сущестовало несколько форм одного класса, пиши, я скажу, как это сделать по описанному выше принципу. Это просто.
З.Ы. Не забудь, что все вышеприведённые функции прописаны именно в модулях соответствующих форм.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
min@y™ (статус: Доктор наук), 3 февраля 2011, 08:53 [#5]:
Цитата (vladrvv):
Потом оказалось, что форм много, они могут открываться из разных мест( меню, бар, из другого окна) и захотелось обобщить код.Написать одну процедуру , через которую производилось создание окна или его активация.
Да и ещё, на счёт синхронизации контролов, пунктов меню и.т.д.
Я юзаю TActionList - это ядро программы по взаимодействию с юзером. Каждой Action присваиваю уникальный номер (Tag), ну и, конечно, устанавливаю нужные свойства, такие как Caption, Hint, Hotkey, ImageIndex, Group, Checked, Enabled и т.д. Класс TAction как раз и служит для синхронизации видимых контролов, у которых есть свойство Action.
Для каждой TAction писать свой обработчик, особенно, если их в проге 100500 штук - это чистый идиотизм. Поэтому я делаю для них единый обработчик и по свойству Tag определяю, на что тыкнул юзер. Вот кусок моей проги по решению Судоку:
procedure TMainForm.ActionExecute(Sender: TObject);
var
// OperationResult: Integer;
NewSudoku: string;
begin
// Обработчик меню и кнопок
case TComponent(Sender).Tag of
// Задать судоку
5: if RussianInputBox('Новое задание', 'Вставь сюда строку:', NewSudoku)
then SetSudoku(NewSudoku);
// Сохранить как изображение
10: if SaveDialog.Execute()
then begin
SaveAsPicture(SaveDialog.FileName, TPictureSaveType(SaveDialog.FilterIndex - 1));
SaveDialog.InitialDir:= ExtractFileDir(SaveDialog.FileName);
end;
// Копировать
20: begin
Clipboard.Open();
try
Clipboard.AsText:= FSolver.Puzzle;
finally
Clipboard.Close();
end;
end;
// Копировать как картинку
22: CopyAsBitmap();
// Вставить
25: if Clipboard.HasFormat(CF_TEXT)
then SetSudoku(Clipboard.AsText);
// Шаг
100: if FSolver.EmptyCellsCount <> 0
then begin
SolvePanel.Tag:= FSolver.Step();
TimePanel.Caption:= '';
PaintBox.Refresh();
end;
// прогон
101: if FSolver.EmptyCellsCount <> 0
then begin
SolvePanel.Tag:= FSolver.Run();
TimePanel.Caption:= FloatToStrF(FSolver.RunTime, ffFixed, 15, 3);
PaintBox.Refresh();
end;
// сброс
110: begin
FSolver.Reset();
PaintBox.Refresh();
FByUser:= False;
SolvePanel.Tag:= 100500;
TimePanel.Caption:= '';
end;
// выход
255: Close();
// Подсказки
301: begin
FSolver.ShowMayBeValues:= ShowMayBeValuesCheckBox.Checked;
PaintBox.Refresh();
end;
// Логирование
302: if LogCheckBox.Checked
then FSolver.Log:= LogMemo.Lines
else begin
FSolver.Log:= nil;
LogMemo.Clear();
end;
end;
end;
З.Ы. Этот и предыдущий посты просто показывают, как делаю я, и никоим образом не являются руководством к действию.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
bugmenot (статус: 3-ий класс), 3 февраля 2011, 10:29 [#6]:
как многа букав...
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
DNK (статус: Студент), 3 февраля 2011, 11:21 [#7]:
TActionList - маст юз, но вот в едином обработчике приятного мало. Вместо 100500 обработчиков мы получим лапшу на 100500 строк. Искать потом по ней, где код для нужного action - занятие на любителя. В случае же индивидуального обработчика достаточно дважды кликнуть нужный action.
Универсальные обработчики использую только в случаях, когда добавление его к новым action не приводит к изменению самого обработчика. Т.е. алгоритм остаётся тотже, новыми будут только параметры.
procedure TMyForm.AutoExecute(Sender: TObject);
begin
MyProcedure(TAction(Sender).Tag);
end;
Если требуется больше одного параметра, то по OnCreate формы кладу в TAction.Tag указатель на необходимые данные.
"Digital Networked Knight"
|
|
Вадим К (статус: Академик), 3 февраля 2011, 11:34 [#8]:
Я вообще против такого использования свойства Tag. Легко запутаться и код не понятен. Потом пол дня ломай голову, почему вызвало не тот что нужно участок кода.
К тому же, процедуры, которые не влазят на один разворот экрана - плохо. их сложно глазами выловить.
Да и зачем делать то, что делфи для нас уже сделало? (я говорю о диспетчеризации событий).
Галочка "подтверждения прочтения" - вселенское зло.
|
|
min@y™ (статус: Доктор наук), 3 февраля 2011, 11:45 [#9]:
Цитата (Вадим К):
Я вообще против такого использования свойства Tag. Легко запутаться и код не понятен. Потом пол дня ломай голову, почему вызвало не тот что нужно участок кода.
Ну, если писать правильно и комментировать код, то не запутываешься. Проверено на мне неоднократно.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
vladrvv (статус: Посетитель), 3 февраля 2011, 19:09 [#10]:
Спасибо всем , кто принял участие в обсуждении вопроса.Но все таки интересно, что неправильно в моем коде?
....
if (FormGL.ActiveMDIChild = Nil) then begin
(fGilec as TForm).Create(Application);
....
Компилируется без замечаний.Где-то очень важная "мелочь" пропущена .
Сейчас остановился на таком варианте:
1) На баре размещаю столько кнопок, сколько окон MDI. На них же вешаю основные процедуры создания или активизации окна.
2) В остальных местах программ, там где надо открыть окно, пишу совсем маленький код , к примеру для кнопки с именем
NameButton
btnNameButton.Click;
|
|
min@y™ (статус: Доктор наук), 3 февраля 2011, 20:43 [#11]:
Цитата (vladrvv):
что неправильно в моем коде?
А ты воспользуйся отладчиком, пройдись по шажочкам по коду, выясни, в какой строке у тебя вылетает AV и какой указатель равен nil или указывает хз-куда. Этой информации нам и не хватает, чтобы хоть как-то въехать в ситуёвину.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
DNK (статус: Студент), 4 февраля 2011, 20:20 [#13]:
vladrvv: У меня конструкция (sNameForm as TForm) не компилируется. Цитата:
Operator not applicable to this operand type
"Digital Networked Knight"
|
|
min@y™ (статус: Доктор наук), 4 февраля 2011, 21:04 [#14]:
Короче, аффтар вопроса нихрена не читает ответы и упрям, как осёл. Может закрыть этот вопрос нахрен?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
min@y™ (статус: Доктор наук), 4 февраля 2011, 21:07 [#15]:
Хренова гора нубов вываливают тут свои позорные исходники и просят найти ошибку. Когда им предлагают решение задачи другим способом - игнорят и минусуют. Ну какого хрена?!
Ну сколько можно, а?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
vladrvv (статус: Посетитель), 5 февраля 2011, 07:49 [#16]:
min@y™
Ну за чем грубить? Спасибо за ценные советы и примеры кода. Я их обязательно учту.+ поставлю.Но в данном случае мне важно выяснить, что неправильно и почему этот код не работает
|
|
DNK (статус: Студент), 5 февраля 2011, 08:46 [#17]:
Цитата (vladrvv):
Но в данном случае мне важно выяснить, что неправильно и почему этот код мой запорожец не работает может долететь до марса
"Digital Networked Knight"
|
|
min@y™ (статус: Доктор наук), 5 февраля 2011, 09:55 [#18]:
Цитата (vladrvv):
Но в данном случае мне важно выяснить, что неправильно и почему этот код не работает
Ну так и что тебе мешает поставить точку останова и пройтись дебаггером по куску кода, посмотреть значеня переменных и понять, где и почему вылетает ошибка? У тебя пальцы сломаны, не можешь на кнопки нажимать? Ну нахрена перекладывать проблему, которую сам можешь решить за 2 минуты, на толпу народа в интернете?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
vladrvv (статус: Посетитель), 7 февраля 2011, 09:01 [#19]:
Проблема решена. Применен прием - поиск класса по имени. Все формы открываеются одной процедурой из любого места.Пример выложен http://zalil.ru/30465772. Кто работает с MDI формами -возможно пригодится.
Тема закрыта
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|