Тайните на Делфи
Тайните на Delphi. Работа с модални форми
Модалните форми се различават от другите форми по това, че когато се показват, достъпът до родителската форма, както и до предварително създадени обекти на приложение, се отказва, докато модалната форма не бъде затворена. Свойството за блокиране на родителската форма е много удобно за използване за създаване на различни диалози и справочници, чиято настройка трябва да изключи промяната на зависимите данни. За съжаление, при първоначалната реализация на този тип форма в Delphi, при създаване на модална форма, поради факта, че достъпът до предварително създадени контроли е забранен, когато модалната форма е минимизирана (иконизирана), предварително създадените елементи на приложението не се минимизират, претрупвайки екрана. Едно от решенията на този проблем може да бъде използването на прихващане на системни съобщения TWMACTIVATEAPP, TWMSYSCOMMAND и извикване на Win API функцията ShowWindow за промяна на състоянието на основната форма на приложението.Отличителна черта на обектното програмиране е възможността за наследяване на класове. В неявна форма този механизъм се използва широко от програмистите при създаване на нови форми или при използване на визуални компоненти. Интересно е да се отбележи, че много програмисти, дори тези със солиден опит, обръщат малко внимание на възможността за повторно използване на веднъж написан код чрез наследяване на създадени преди това общи обекти. Не вземам предвид визуалните компоненти в това. Това се отнася за собствените разработки на програмиста.
Нека се опитаме да създадем шаблон за нашите модални форми, който прилага решение на описания по-горе проблем за контролиране на сгъването и разгъването на основната форма на приложението от модалната форма. Нека създадем нова форма от тип TfrmModal, която наследява класа Tform. Даден е текстът на модула на тази формаПо-долу:
интерфейс използва Windows, съобщения, SysUtils, класове, графики, контроли, формуляри, диалози;
type TfrmModal = class(TForm) private procedure WMSYSCOMMAND(var Msg: TWMSYSCOMMAND); съобщение WM_SYSCOMMAND; procedure WMACTIVATEAPP(var Msg: TWMACTIVATEAPP); съобщение WM_ACTIVATEAPP; край;
procedure TfrmModal.WMACTIVATEAPP(var Msg: TWMACTIVATEAPP); begin //Ако приложението е минимизирано, //тогава се разширява до нормално if IsIconic(Application.Handle) then ShowWindow(Application.Handle, SW_RESTORE); inherited; end;
процедура TfrmModal.WMSYSCOMMAND(var Msg: TWMSYSCOMMAND); begin //Ако съобщението е "свиване", // тогава свиване на основния формуляр за приложение if Msg.CmdType = SC_MINIMIZE then ShowWindow(Application.Handle, SW_MINIMIZE) else inherited; край; край.
Желателно е да запазите създадената заготовка в отделна директория, достъпна за всички ваши проекти. За целта е желателно да създадете директорията $(DELPHI)\Projects\common.
За да тестваме създадената заготовка, нека създадем нов проект, например $(DELPHI)\Projects\TestModalForm\ TestModal.dpr. Чрез извикване на менюто „Проект-Добавяне към проект“, добавете създадения преди това формуляр $(DELPHI)\Projects\common\frmuModal към проекта. В този случай този формуляр трябва да бъде премахнат от списъка с автоматично създадени формуляри в меню "Проект-Опции", раздел "Формуляри".
Практиката в програмирането показва, че е желателно да оставите само основната форма и модулите с данни в списъка с автоматично създадени форми. Желателно е да създавате други форми динамично, ако е необходимо. Това изисква по-малко системни ресурси, ускорява зареждането на програмата и, най-важното, намалява вероятността от грешки, свързани с неконтролирано възникване на събитие при използване на общиресурси в няколко форми. Пример е използването на някакъв наследник на TDataset от няколко форми.
За динамично създаване на модални форми можете да използвате проста конструкция, пример за която е показан в списъка:
if Not Assigned(frmNewModal) then Application.CreateForm(TfrmNewModal,frmNewModal); try if (frmMyForm.ShowModal = mrOk) then //Извършете някои действия finally frmMyForm.Free; frmMyForm :=nil; //Може да бъде заменен с FreeAndNeel( frmMyForm); край;
Бих искал да отбележа, че когато модалният диалог е затворен, се връща резултат от типа TModalResult. Едно приложение може да приеме всяка целочислена стойност като модален резултат. За по-лесно използване системата дефинира няколко стойности от този тип, показани в таблицата.Сега е време да използвате предварително създадената заготовка. Нека добавим нова форма към проекта, която наследява създадения преди това клас модална форма. За да направите това, изберете елемента от менюто Файл - Нов. В диалоговия прозорец, който се появява, изберете раздела с името на проекта и изберете формуляра frmModal от списъка с формуляри на проекта. Също така ще премахнем този формуляр от списъка с автоматично създадени формуляри. Нека добавим метод за създаване на нов формуляр:
//** Създайте екземпляр на формуляра и го покажете модално procedure ShowNewModalForm; begin // Първо проверете за екземпляр // от този клас if Not Assigned(frmNewModal) then Application.CreateForm(TfrmNewModal,frmNewModal); try frmNewModal.ShowModal; накрая frmNew Modal.Free; frmNewModal:=нула; край; край;
Добавете връзка към новия модул за модална форма и бутон за извикване на създадения преди това метод ShowNewModalForm към основната форма на приложението. Компилираме създадения проект и го пускаме за изпълнение. При щракваненашата модална форма се извиква на бутона. Освен това, като щракнете върху бутона "свиване", не само модалната форма се минимизира, но и основната форма на приложението (вижте фигурата).В резултат на тези прости манипулации получихме нов клас, който изпълнява посочените функции и скрива изпълнението на тези функции. Наследяването на класове опростява разработването на програми и в същото време няма нужда да повтаряте един и същ блок код многократно. Естествено, това намалява броя на грешките в програмата.