Глава 8. Объекты приложения
При разработке приложения ObjectWindows вам нужно сначала
определить объект приложения, производный от типа ObjectWindows
TApplication. Этот объект инкапсулирует следующее поведение при-
ложения ObjectWindows:
* Создание и вывод основного окна приложения.
* Инициализацию первого экземпляра приложения для задач, вы-
полняемых всеми экземплярами приложения, таких как созда-
ние файлов, совместно используемых всеми экземплярами.
* Инициализацию каждого экземпляра приложения, например,
загрузку таблицы оперативных клавиш.
* Обработку сообщений Windows.
* Закрытие приложения.
Кроме определения объекта приложения вы должны добавить к
нему возможность построения объекта основного окна. Вы имеете
также возможность переопределения используемого по умолчанию по-
ведения инициализированных экземпляров, закрытия приложения и об-
работки сообщений Windows.
Минимальные требования
-----------------------------------------------------------------
Чтобы ваше программа ObjectWindows стала рабочим приложением
Windows, она должна в своем основном блоке beginend делать сле-
дующее:
- выполнять инициализацию;
- обрабатывать сообщения;
- по требованию завершать работу.
Используемый по умолчанию объект выполняет эти задачи путем
вызова трех его методов: Init, Run и Done. Основной блок любой
программы ObjectWindows содержит обычно эти три метода. Чтобы из-
менить поведение по умолчанию, методы нужно переопределить.
Поиск объекта приложения
-----------------------------------------------------------------
Когда программа выполняется, ObjectWindows поддерживает гло-
бальную переменную Application - указатель на объект приложения.
Этот указатель позволяет подпрограммам вне объекта приложения об-
ращаться к его полям и методам. По умолчанию Application устанав-
ливается в @Self конструктором объекта приложения и в nil дест-
руктором объекта.
Минимальное приложение
-----------------------------------------------------------------
Приведем пример минимального приложения ObjectWindows:
program MinApp;
uses OWindows;
var
MyApp: TApplication;
begin
MyApp.Init('TtstApp');
MyApp.Run;
MyApp.Done;
end;
MinApp - это абсолютный минимум приложения ObjectWindows.
Эта программа не требует определения других объектов. Обычно вы
определяете новый объектные типы как минимум для приложения и ос-
новного окна.
Методы Init, Run и Done
-----------------------------------------------------------------
Так как в основном блоке программы ObjectWindows каждый раз
используются одни и те же операторы, вы должны понимать, что де-
лает каждый из них.
Конструктор Init
-----------------------------------------------------------------
Первый оператор - это вызов конструктора Init приложения.
Этот вызов делает следующее:
* Строит объект.
* Инициализирует поля данных объекта.
* Устанавливает глобальную переменную Application на объект
(@Self).
* Выполняет два вида инициализации:
- Вызывает InitApplication при отсутствии других выполняе-
мых экземпляров данного приложения.
- Всегда вызывает InitInstance, устанавливая вызовом
InitMainWindow основное окно.
Когда Init завершает работу, основное окно вашего приложения
находится на экране. В большинстве случаев вам нужно только пере-
определить InitMainWindow.
Метод Run
-----------------------------------------------------------------
Второй оператор вызывает метод Run приложения, который реа-
лизует работу приложения, вызывая MessageLoop. MessageLoop обра-
батывает сообщения от Windows и выполняет инструкции, которые уп-
равляют работой приложения. MessageLoop - это цикл, который про-
должает работу до закрытия приложения.
MessageLoop вызывает несколько методов, обрабатывающих конк-
ретные поступающие сообщения (см. далее).
Деструктор Done
-----------------------------------------------------------------
Done - это деструктор объекта приложения. Перед завершением
работы приложения он освобождает память объекта приложения.
+----------------+ +-----------------+
| Init +--+->| InitApplication |
+----------------+ | +-----------------+
|
| +-----------------+ +----------------+
+->| InitInstance +--->| InitMainWindow |
+-----------------+ +----------------+
+----------------+ +-----------------+
| Run +---->| MessageLoop |
+----------------+ +-----------------+
+----------------+
| Done |
+----------------+
Рис. 8.1 Вызовы методов, управляющие работой приложения.
Инициализация приложения
-----------------------------------------------------------------
Выполнение методов, инициализирующих объект приложения, поз-
воляет вам настроить части процесса путем переопределения отдель-
ных методов. Один из методов, требующий переопределения, чтобы
приложения получило конкретный смысл - это InitMainWindow. Вы мо-
ете также переопределить InitInstance и InitApplication.
Инициализация основного окна
-----------------------------------------------------------------
Вы должны определить метод InitMainWindow, который строит и
инициализирует объект основного окна и сохраняет его в поле
MainWindow объекта приложения. Ниже показан пример описания объ-
екта приложения и метода InitMainWindow.
Данный метод создает новый экземпляр типа TWindow
ObjectWindows (PWindow - это указатель на тип TWindow). Обычно
ваша программа будет определять для своего основного окна новый
оконный тип, а InuitMainWindow будет использовать этот тип вмес-
то TWindow.
Примечание: Объекты окон подробно описываются в Главе
10.
Следующее простое приложение ObjectWindows объединяет в себе
новый тип TMyApplication и старое приложение MinApp. Оно отлича-
ется от MinApp только тем, что основное окно имеет заголовок:
program TestApp;
uses OWindows;
type
TMyApplication = object(TApplication)
procedure InitMainWindow; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
MainWindow := New(PWindow, Init(nil, 'Основное окно'));
end;
var
MyApp: TApplication;
begin
MyApp.Init('TestApp');
MyApp.Run;
MyApp.Done;
end;
Программа TestApp выводит окно с заголовком 'Основное окно'.
Вы можете легко перемещать это окно и изменять его размер, мини-
мизировать его, восстанавливать или максимизировать. Закрытие ок-
на завершает приложение. Короче, TestApp - это полнофункциональ-
ный "скелет" приложения, оснащенный только простейшим основным
окном.
Специальный вывод основного окна
-----------------------------------------------------------------
Начальный вывод основного окна управляется переменной
CmdShow модуля System. CmdShow содержит одну из констант sw_ и
передается в качестве параметра функции API Windows ShowWindow,
когда приложение создает свое основное окно.
С помощью CmdShow вы легко можете вывести основное окно в
нормальном виде (по умолчанию), распахнутым до размеров полного
экрана, минимизированным в пиктограмму или скрытым. Лучшим местом
присваивания значения CmdShow является конструктор объекта основ-
ного окна. Это обеспечивает передачу выбранного значения при соз-
дании элемента экрана.
Инициализация первого экземпляра
-----------------------------------------------------------------
Если пользователь запускает приложение в отсутствии уже ра-
ботающих других экземпляров этого приложения, вы можете опреде-
лить для такого первоначального запуска некоторую обработку. Эта
обработка называется инициализацией первого экземпляра. Если
пользователь начинает и завершает ваше приложение, затем запуска-
ет его снова и т.д., каждый экземпляр будет первым экземпляром
(поскольку другие экземпляры в этот момент не выполняются).
Если текущим экземпляром является первый экземпляр, то конс-
труктор Init вызывает InitApplication. TApplication определяет
заместитель метода InitApplication, который вы можете для выпол-
нения специальной инициализации первого экземпляра переопреде-
лить.
Например, вы можете модифицировать TestApp таким образом,
чтобы о первом экземпляре сообщалось в заголовке основного окна.
Для этого добавьте в тип приложения TMyApplication булевское поле
с именем FirstApp, затем переопределите метод InitApplication,
чтобы он устанавливал FirstApp в True. Наконец, модифицируйте
InitMainWindow для проверки FirstApp и вывода в основном окне
приложения соответствующего заголовка (см. Рис. 8.2).
#################################################################
#+----------------------------------------------------+-+-+######
#|#=###############Первый экземпляр###################|^|v|######
#+----------------------------------------------------+-+-|######
#| |######
#| +----------------------------------------------------+-+-+###
#| |#=###############Дополнительный экземпляр###########|^|v|###
#| +----------------------------------------------------+-+-|###
#| | |###
#| | +----------------------------------------------------+-+-+
#| | |#=#XXXXXXXXXXXXДополнительный экземплярXXXXXXXXXXXXX|^|v|
#| | +----------------------------------------------------+-+-|
#| | | |
#| | | |
#+--| | |
####| | |
####+--| |
#######| |
#######+--------------------------------------------------------+
Рис. 8.2 Новая инициализация приложения.
program TestApp;
uses OWindows;
type
TMyApplication = object(TApplication)
FirstApp: Boolean;
procedure InitMainWindow; virtual;
procedure InitApplication; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
if FirstApp then
MainWindow := New(PWindow, Init(nil,
'Первый экземпляр'))
else MainWindow := New(PWindow, Init(nil,
'Дополнительный экземпляр'));
end;
procedure TMyApplication.InitApplication;
begin
FirstApp := True;
end;
var MyApp; TMyApplication;
begin
MyApp.Init('TestApp');
MyApp.Run;
MyApp.Done;
end.
Инициализация каждого экземпляра
-----------------------------------------------------------------
Пользователь может одновременно выполнять несколько экземп-
ляров ObjectWindows. Метод InitInstance инициализирует каждый эк-
земпляр приложения. Он должен инициализировать только само прило-
жение, а не его основное окно. Основное окно инициализируйте в
InitMaionWindow.
InitInstance вызывает InitMainWindow, а затем создает и вы-
водит основное окно. Для модификации стандартной инициализации
приложения (например, для загрузки таблицы оперативных клавиш)
вам нужно только переопределить InitInstance. Если вы переопреде-
ляете для своего приложения InitInstance, убедитесь сначала, что
он вызывает метод InitInstance, наследуемый из TApplication.
Приведем метод InitInstance, который перед выполнением при-
ложения загружает метод InitInstance. 'MeHotKeys' - это идентифи-
катор ресурса таблицы оперативных клавиш, определенный в файле
ресурса:
procedure TEditApplication.InitInstance;
begin
inherited InitInstance;
HAccTable := LoadAccelerators(HInstance, 'MyHotKeys');
end;
Вы можете также использовать InitInstance для регистрации
экземпляра приложения с внешней DLL (типа Paradox Engine).
Выполнение приложений
-----------------------------------------------------------------
Метод Run вашего приложения вызывает метод MessageLoop, ко-
торый вызывает цикл обработки сообщений вашей программы. Во время
выполнения вашей программы в цикле обработки сообщений обрабаты-
ваются поступающие от Windows сообщения. Программы ObjectWindows
наследуют цикл MessageLoop, который работает автоматически. До-
полняйте цикл обработки сообщений только специальными диалогами,
оперативными клавишами или обработкой MDI.
Метод MessageLoop для обработки сообщений Windows вызывает
три метода. ProcessDlgMsg работает с безрежимными диалоговыми ок-
нами, ProcessAccels - обрабатывает оперативные клавиши, а
ProcessMDIAccels - оперативные клавиши для приложений MDI. Для
приложений, не использующих командные клавиши или безрежимные ди-
алоговые окна или не являющихся приложениями MDI MessageLoop мож-
но несколько упростить. См. методы TApplication в Главе 21.
Закрытие приложений
-----------------------------------------------------------------
Вызов деструктора Done в основной программе вашего приложе-
ния уничтожает объект приложения. Однако, перед тем как это про-
исходит, программа должна прервать цикл обработки сообщения. Это
может произойти, когда пользователь пытается закрыть основное ок-
но приложения. Мы говорим, что это может произойти, так как
ObjectWindows предусматривает механизм изменения поведения прило-
жения при закрытии: вы можете задавать условия закрытия.
Модификация поведения при закрытии
-----------------------------------------------------------------
Все оконные объекты, наследуют булевский метод CanClose,
возвращающий по умолчанию True (что указывает на подтверждение
закрытия, то есть TestApp закрывается немедленно). Для изменения
поведения при закрытии вы можете переопределить методы CanClose
приложения или основного типа окна. Если какие-либо объекты возв-
ращают из CanClose значение False, то приложение завершиться не
может. Обычно вы можете изменить поведение при закрытии объектно-
го типа основного окна. Например, перед завершением можно убе-
диться, что приложение сохранило файлы.
Механизм CanClose
Механизм CanClose дает основному окну, объекту приложения и
другим окнам возможность подготовиться с закрытию или предотвра-
тить его. В итоге объект приложения должен разрешить закрытие
приложения. По умолчанию он проверяет основное окно. Обычная пос-
ледовательность закрытия выглядит следующим образом:
1. Windows посылает основному окну приложения сообщение
wm_Close.
2. Объект основного окна вызывает метод CanClose объекта
приложения.
3. Объект приложения вызывает метод CanClose.
4. Объект основного окна вызывает метод CanClose для каждого
из дочерних окон и возвращает True только в том случае,
если методы CanClose дочерних окон возвращают True.
Модификация CanClose
Методы CanClose редко возвращают значение False. Вместо это-
го они должны выполнять некоторые действия, позволяющие им возв-
ращать True. Метод CanClose должен возвращать False только в том
случае, если он не может выполнить действий, необходимых для нор-
мального завершения, или пользователь показывает, что он хочет
продолжать выполнение программы.
Например, метод CanClose окна редактора может проверять из-
менение редактируемого текста, а затем выводить диалоговое окно с
запросом, нужно ли сохранить текст перед закрытием, и восприни-
мать ответ Yes (Да), No (Нет) или Cancel (Отмена). Cancel будет
указывать, что пользователь пока не хочет закрывать приложение,
так что CanClose должен возвращать False. CanClose следует также
возвращать False при обнаружении ошибки в сохранении текста, пре-
доставляя пользователю другую возможность сохранения данных перед
закрытием.
Если метод CanClose не переопределяется, тип основного окна
наследует его от TWindowsObject, где CanClose возвращает True
после вызовов методов CanClose дочерних окон. Чтобы модифициро-
вать поведение при закрытии основного окна, переопределите метод
CanClose. Например, для проверки того, что пользователь собирает-
ся закрыть окно, он может проверять открытые файлы.
Назад | Содержание | Вперед