История переиздания | ||
---|---|---|
Издание 1.0 | Сентябрь 2003 г. |
Модальные формы отличаются от других форм тем, что при выводе ее на экран, доступ к родительской форме, а так же к ранее созданным объектам приложения запрещается до момента закрытия модальной формы. Свойство блокировки родительской формы очень удобно использовать для формирования различных диалогов, а так же справочников, корректировка которых должна исключать изменение зависимых данных. Но в базовой реализации данного типа форм в Delphi есть один существенный недостаток. При сворачивании (иконофикации) модальной формы, ранее созданные элементы приложения не сворачиваются.
Одним из вариантов решения этой проблемы может быть использование перехвата системных сообщений WM_ACTIVATEAPP, WM_SYSCOMMAND и вызова Win API функции ShowWindow для изменения состояния главной формы приложения.
Отличительной особенностью объектного программирования является возможность наследования классов. В неявном виде этот механизм повсеместно используется программистами при создании новых форм или при использовании визуальных компонент. Интересно отметить, что многие программисты, даже с солидным стажем мало уделяют внимания возможности повторного использования единожды написанного кода путем наследования ранее созданных типовых объектов. Я не рассматриваю при этом визуальные компоненты. Здесь имеется в виду собственные наработки программиста. Попробуем создать заготовку для наших модальных форм, реализующую решение ранее описанной проблемы управления сворачиванием и разворачиванием главной формы приложения из модальной формы. Создадим новую форму типа TfrmModal наследующую класс Tform. Текст модуля данной формы приведен ниже:
unit frmuModal; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TfrmModal = class(TForm) private procedure WMSYSCOMMAND(var Msg: TWMSYSCOMMAND); message WM_SYSCOMMAND; procedure WMACTIVATEAPP(var Msg: TWMACTIVATEAPP); message WM_ACTIVATEAPP; end; var frmModal: TfrmModal; implementation {$R *.DFM} procedure TfrmModal.WMACTIVATEAPP(var Msg: TWMACTIVATEAPP); begin //Если приложение в свернутом состоянии, //то разворачиваем в нормальное if IsIconic(Application.Handle) then ShowWindow(Application.Handle, SW_RESTORE); inherited; end; procedure TfrmModal.WMSYSCOMMAND(var Msg: TWMSYSCOMMAND); begin //Если сообщение "свернуть", // то сворачиваем главную форму приложения if Msg.CmdType = SC_MINIMIZE then ShowWindow(Application.Handle, SW_MINIMIZE) else inherited; end; end.
Созданную заготовку желательно сохранить в отдельный каталог, доступный всем Вашим проектам. Для этого желательно создать каталог $(DELPHI)\Projects\common.
Для тестирования созданной заготовки создадим новый проект, например $(DELPHI)\Projects\TestModalForm\ TestModal.dpr. Вызвав меню «Project-Add to project» добавим в проект ранее созданную форму $(DELPHI)\Projects\common\frmuModal. При этом данную форму нужно удалить из списка автоматически создаваемых форм в меню «Project-Options» закладка «Forms».
Практика программирования показывает, что в списке автоматически создаваемых форм желательно оставлять только главную форму и модули данных. Остальные формы желательно создавать динамически по мере необходимости. При этом требуется меньше системных ресурсов, ускоряется загрузка программы, и что самое главное снижается вероятность появления ошибок, связанных с неконтролируемым вызовом событий при использовании общих ресурсов несколькими формами. Примером является использование некоторого наследника TDataset несколькими формами.
Для динамического создания модальных форм можно использовать простую конструкцию, пример которой показан в листинге:
if Not Assigned(frmNewModal) then Application.CreateForm(TfrmNewModal,frmNewModal); try if (frmMyForm.ShowModal = mrOk) then //Выполняем некоторые действия finally frmMyForm.Free; frmMyForm :=nil; //Можно заменить функцией FreeAndNeel(frmMyForm); end;
Хочется обратить внимание, что при закрытии модального диалога, возвращается результат типа TModalResult. Приложение может воспринимать любое целочисленное значение в качестве модального результата. Для удобства использования, в системе определены несколько значений данного типа приведенные в таблице:
Таблица 1. Значения результатов TModalResult
Константа | Значение | Описание |
---|---|---|
mrNone | 0 | Используется как значение по умолчанию |
mrOk | idOK | Выход по нажатию кнопки типа OK |
mrCancel | idCancel | Выход по нажатию кнопки типа CANCEL |
mrAbort | idAbort | Выход по нажатию кнопки типа ABORT |
mrRetry | idRetry | Выход по нажатию кнопки типа RETRY |
mrIgnore | idIgnore | Выход по нажатию кнопки типа IGNORE |
mrYes | idYes | Выход по нажатию кнопки типа YES |
mrNo | oidN | Выход по нажатию кнопки типа NO |
mrAll | mrNo + 1 | Используется для определения последней предустановленной константы |
Теперь настало время воспользоваться ранее созданной заготовкой. Добавим в проект новую форму, наследующую ранее созданный класс модальной формы. Для этого выберем пункт меню File – New. В появившемся диалоге выберем закладку с именем проекта, и выберем в списке форм проекта форму frmModal. Данную форму так же уберем из списка автоматически создаваемых форм. Добавим метод создания новой формы:
//** Создаем экземпляр формы и выводим ее модально procedure ShowNewModalForm; begin // Предварительно проверяем, на наличие экземпляра // данного класса if Not Assigned(frmNewModal) then Application.CreateForm(TfrmNewModal,frmNewModal); try frmNewModal.ShowModal; finally frmNewModal.Free; frmNewModal:=nil; end; end;
В главную форму приложения добавим ссылку на модуль новой модальной формы и кнопку вызова ранее созданного метода ShowNewModalForm. Компилируем созданный проект и запускаем его на выполнение. По нажатию на кнопку вызывается наша модальная форма. Причем по нажатию на кнопке «свернуть» сворачивается не только модальная форма, но и главная форма приложения.
В итоге этих нехитрых манипуляций мы получили новый класс, реализующий заданные функции и скрывающий реализацию этих функций.
Наследование классов позволяет упростить разработку программ, и при этом отпадает необходимость в многократном повторении одного и того же блока кода. Естественно при этом снижается количество ошибок в программе.