Глава 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. Например, для проверки того, что пользователь собирает-
        ся закрыть окно, он может проверять открытые файлы. 
                              Назад | Содержание | Вперед