| История переиздания | ||
|---|---|---|
| Издание 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. Компилируем созданный проект и запускаем его на выполнение. По нажатию на кнопку вызывается наша модальная форма. Причем по нажатию на кнопке «свернуть» сворачивается не только модальная форма, но и главная форма приложения.
В итоге этих нехитрых манипуляций мы получили новый класс, реализующий заданные функции и скрывающий реализацию этих функций.
Наследование классов позволяет упростить разработку программ, и при этом отпадает необходимость в многократном повторении одного и того же блока кода. Естественно при этом снижается количество ошибок в программе.