В следующих нескольких главах мы построим графическую интерактивную программу Windows, дополненную меню, средствами сохранения и загрузки файлов, графикой и отображением текста, а также специализированными управляющими элементами. По ходу дела вы познакомитесь с основными принципами проектирования программы Windows, такими как обработка сообщений, управление дочерним и порождающим окном и автоматическое повторное отображение графики.
    Этот процесс разбит на следующие шаги:
    Исходный код приложения для различных этапов вы можете найти на дистрибутивных дисках. Описываемым в руководстве шагам соответствуют файлы STEP01.PAS, STEP02.PAS и так далее (можно найти также промежуточные программы).
    Отправным пунктом для всех программ, которые
вы пишете с
применением ObjectWindows, является программа STEP01A.PAS. Эта
программа, которая называется Steps, создает основное окно приложения.
    Все программы ObjectWindows должны использовать
модуль
OWindows, который содержит стандартные объекты, используемые
ObjectWindows для приложений и окон. Большинство приложений включают в
себя также диалоговые блоки и соответствующие управляющие
элементы. ObjectWindows предусматривает для них объекты в модуле
ODialogs. Объекты, относящиеся к печати, находятся в модуле
OPrinter. Программам, применяющим наборы и потоки, необходим модуль
Objects.
    Кроме модулей ObjectWindows большинству программ
необходимы
также модули WinTypes и WinProcs. Эти два модуля определяют типы
и константы (WinTypes) и процедуры и функции (WinProcs), образующие
прикладной программный интерфейс Windows (API). Приложениям,
использующим продвинутые средства Windows (версий старше 3.0),
кроме данных двух нужны также другие модули.
    ечание: Обзор модулей ObjectWindows вы можете найти в
Главе 7 "Иерархия ObjectWindows".
    Все приложения Windows имеют основное окно,
которое выводится при запуске программы пользователем. Пользователь
выходит из
приложения, закрывая основное окно. В приложении ObjectWindows
основное окно представляет собой объект окна. Этот объект принадлежит
объекту приложения, который отвечает за создание и вывод на
экран основного окна, обработку сообщений Windows и завершение
программы. Объект приложения действует как объектно-ориентирован-
ная замена самого приложения. Аналогично, чтобы сделать скрытыми
детали программирования в Windows, ObjectWindows предусматривает
окно, диалоговый блок и другие объектные типы.
    Каждая программа ObjectWindows должна определять
новый тип
приложения, являющегося наследником предоставляемого типа
TApplication. В программе Steps этот тип называется
TMyApplication. Приведем основной блок программы Steps:
    Init - это конструктор TMyApplication, создающий новый
объект MyApp. Он позволяет также задать имя приложения (поле объекта)
'Steps' и создает (и выводит) основное окно приложения. Run
запускает последовательность вызовов методов, составляющих ход
выполнения приложения Windows. Done - это деструктор
TMyApplication.
    Примечание: Объекты приложения подробно описываются в
Главе 8.
    Определение TMyApplication имеет следующий вид:
    InitMainWindow отвечает за построение объекта окна,
используемого в качестве основного окна программы. Этот объект основного
окна хранится в поле объекта приложения MainWindow. Объекту
приложения принадлежит объект основного окна, но эти два объекта
не являются родственными в иерархии наследования.
    Пока программа Steps просто выводит на экран
пустое окно,
которое можно перемещать по экрану, изменять его размер, минимизировать,
максимизировать и закрывать. Приведем полный листинг программы Steps,
которую мы получили к данному моменту:
    Пока программа Steps состоит из двух объектов -
объекта приложения и объекта окна. Объект приложения (MyApp) является
экземпляром TMyApplication - типом, производным от TApplication.
Оконный объект, который содержится в поле MainWindow объекта
MyApp, является экземпляром TWindow (общее окно ObjectWindows).
Во всех программах, кроме простейших, вам нужно определить тип
своего основного окна, соответствующий поведению приложения. В
данном разделе мы выведем на экран основное окно, тип которого
является производным от TWindow.
    Приложения: Более подробно об основном окне
рассказывается в Главе 8 "Объекты приложения".
    Объект приложения инкапсулирует стандартное поведение
приложения Windows, включая построение основного окна. Тип
TApplication обеспечивает фундаментальное поведение для каждого
создаваемого вами приложения.
    Аналогично, объект окна инкапсулирует поведение,
реализуемое приложениями ObjectWindows, включая их основные окна. Это
поведение включает в себя вывод на экран, изменение размера и закрытие;
ответ на пользовательские события, такие как щелчок кнопкой "мыши",
буксировку и выбор пунктов меню; вывод управляющих элементов, таких как
блоки списка и командные кнопки. Тип TWindow и его
предок TWindowsObject предусматривают для данного базового поведения
методы и поля.
    Примечание: Объекты окна подробно описываются в
Главе 10 "Объекты окна".
    Чтобы сделать ваши программы полезными и интересными,
вам нужно создать новый тип, производный от TWindow. Новый тип наследует
поля и методы TWindow и добавляет часть своих. В общем случае
объектно-ориентированный подход позволяет вам не "изобретать"
каждый раз окно.
    Объект окна имеет по крайней мере три поля:
HWindow. Parent и ChildList. HWindow содержит описатель окна.
Описатель окна - это уникальное число, которое связывает интерфейсный
объект (такой как окно, диалоговый блок или объект управляющего элемента) с
соответствующим элементом экрана.
    Примечание: Подробно об описателях окна их
использовании рассказывается в Главе 10 "Объекты окна".
    Таким образом, HWindow содержит целое значение,
идентифицирующее соответствующий элемент экрана. Это напоминает бирку на
связке ключей. Аналогично тому как вы выбираете ключ, чтобы достать из
шкафа пальто, вы выбираете описатель для получения окна.
В большинстве случаев вы работаете с объектами окна, и у вас нет
необходимости манипулировать описателем окна непосредственно, но
они используются при вызове функций Windows. Например, на данном
шаге вы вызываете функцию MessageBox. Эта функция требует указания
параметра, идентифицирующего порождающее окно сообщений. Вы
указываете основное окно, описатель которого записан в его поле
HWindow:
    Большинство приложений используют несколько окон,
и, чтобы они взаимодействовали, их требуется связать. Например, когда вы
завершаете приложение, оно должно иметь способ очистки всех окон,
за которые отвечает. В общем случае Windows справляется с этим,
связывая окна как дочернее и порождающее. Порождающее окно отвечает за
свое дочернее окно. ObjectWindows предусматривает для
каждого объекта окна поля для отслеживания порождающего и дочерних окон.
    Примечание: Взаимодействие этих окон подробнее
описывается в Главе 9.
    Поле Parent содержит указатель на порождающий оконный
объект. Это не порождающее окно в смысле предка, а скорее окно-владелец.
Взаимосвязь этих окон описывается в шаге 10.
    Третье поле оконного объекта - это поле ChildList,
содержащее связанный список дочерних окон.
    Теперь у вас есть некоторое представление о том,
что содержит оконный объект, и вы можете создать новый оконный тип,
производный от TWindow, используя его как основное окно программы
Step. Сначала измените определения и задайте новый тип
TStepWindow. Не забудьте также определить новый указатель на тип
TStepWindow - PStepWindow, который будет полезен при создании экземпляров
объектов TStepWindow.
    Примечание: MAkeWindow поясняется в Главе 9
"Интерфейсные объекты".
    Однако TStepWindow не определяет новых видов поведения,
отличных от тех, которые наследуются от TWindow и TWindowObject.
Другими словами, программа Step не становится более интересной.
Такие виды поведения будут добавлены в следующем разделе.
    Скорейший способ сделать оконный объект полезным
- это заставить его отвечать на некоторые сообщения Windows. Например,
когда вы щелкаете "мышью" в основном окне программы Step, Windows
посылает окну сообщение wm_LButtonDown, которое перехватывается
ObjectWindows и посылается затем соответствующему оконному объекту.
Это указывает оконному объекту, что пользователь щелкнул в
нем кнопкой "мыши". При этом передаются также координаты точки,
где пользователь нажал кнопку. (Эту информацию мы используем в
шаге 2.)
    Примечание: Сообщения Windows определены в модуле
WinTypes.
    Аналогично, когда пользователь щелкает правой
кнопкой "мыши", основной оконный объект получает сообщение wm_RButtonDown,
переданное Windows. На следующем шаге мы узнаем, как сделать так,
чтобы основное окно (экземпляр TStepWindow) отвечало на эти сообщения
и делало что-нибудь полезное.
    Чтобы перехватывать сообщения Windows и отвечать
на них, для каждого типа поступающего сообщения, на которое вы хотите
реагировать, вам нужно определить метод оконного объекта. Такие методы
называются методами реакции на сообщение. Чтобы определить заголовок
определения метода как метод реакции, нужно добавить к виртуальному методу
расширение, представляющее собой идентификатор
сообщения, на которое нужно реагировать. Например, определенный
ниже метод реагирует на все сообщения wm_LButtonDown.
    Все сообщения в Windows, включая системные
сообщения Windows
и команды меню, представляются в виде чисел. Каждый метод реакции
на сообщение должен иметь уникальное число, так что для сообщений
Windows и команд, если они имеют одинаковые номера, вызываются
различные методы.
    Чтобы облегчить для вас эту задачу, ObjectWindows
определяет
для каждого вида сообщений константы: wm_First для сообщений
окон, cm_First для командных сообщений и nf_First для уведомляющих
сообщений. Подробнее об этих константах рассказывается в Главе 7,
но сейчас нужно только помнить, что когда вы пишете метод
реакции на сообщение, начинающееся с wm_, к нему добавляется
wm_First.
    Msg - это запись типа TMessage, содержащая такую
информацию, как координаты точки, где была нажата кнопка "мыши".
Все методы
реакции на сообщение должны воспринимать один параметр-переменную
типа TMessage. Аргумент Msg мы рассмотрим в программе Step позднее.
    В данный момент вы можете просто определить методы
реакции,
которые выводят на экран окно сообщения о нажатии кнопки "мыши".
Позднее вы сможете добавить более полезную реакцию. Приведем определение
метода реакции на нажатие левой кнопки "мыши":
    Программа Steps завершает выполнение, когда
пользователь
дважды щелкает "мышью" в блоке управляющего меню основного окна -
маленьком квадрате в левом верхнем углу. Окно и приложение немедленно
закрываются. Такое поведение годится для простых программ,
но может вызвать затруднения в более сложных случаях.
    Перед выходом хорошо написанное приложение всегда
спрашивает, хочет ли пользователь сохранить несохраненные результаты работы.
Такой вид поведения вы легко можете добавить в свою прикладную программу
ObjectWindows. Начните со Step и добавьте двойную проверку запроса
пользователя на выход.
    Когда пользователь пытается закрыть приложение
ObjectWindows, Windows посылает основному окну сообщение
wm_Close, которое вызывает метод CanClose приложения. CanClose -
это булевская функция, указывающая, можно ли завершить (OK) приложение
(True). По умолчанию метод CanClose наследуется из вызова
TApplication метода CanClose основного оконного объекта. В большинстве
случаев решение о закрытии (OK) принимается объектом основного окна.Шаг 1: Создание базового приложения
Step 1 Basic App Базовая программа Step 2 Text Текст Step 3 Lines Строки Step 4 Menu Меню Step 5 About Box Об окне Step 6 Pens Перья Step 7 Painting Рисование Step 8 Streams Потоки Step 9 Printing Печать Step 10 Palette Палитра Step 11 BWCC Управляющие элементы окна Step 12 Custom ctrls Специализированные
элементы
var
MyApp: TMyApplication;
begin
MyApp.Init('Steps');
MyApp.Run;
MyApp.Done;
end.
Определение типа приложения
type
TMyApplication = object(TApplication)
procedure InitMainWindow; virtual;
end;
Инициализация основного окна
precedure TMyApplication.InitMainWindow;
begin
MainWindow := New(PWindow, Init(nil, 'Steps'));
end;
    Обычно метод InitMainWindow модифицируется для
создания нового типа основного окна. Указанный метод использует экземпляр
объекта TWindow - предоставляемый ObjectWindows тип окна, который
определяет наиболее общее окно. На шаге 2 мы заменим его более
интересным оконным типом.
program Steps;
uses OWindows;
type
TMyApplication = object(TApplication)
procedure InitMainWindow; virtual;
end;
procedure TMyApplication.InitMainWindow;
begin
MainWindows := New(PWindow, Init(nil, 'Steps'));
end;
var MyApp: TMyApplication;
begin
MyApp.Init('Steps');
MyApp.Run;
MyApp.Done;
end.
Объект основного окна
Что такое объект окна?
Описатели
MessageBox(MainWindow^.HWindow, 'Хотите сохранить?',
'Файл не изменен', mb_YesNo or mb_IconQuestion);
Порождающие и дочерние окна
Создание нового типа окна
type
PStepWindow = ^TStepWindow;
TStepWindow = object(TWindow)
end;
    Затем измените TMyApplication.InitMainWindow,
чтобы создать в качестве основного окна вместо TWindow TStepWindow.
procedure TMyApplication.InitMainWindow;
begin
Main := New(PStepWindow, Init(nil, 'Step'));
end;
    Определение нового типа и создание его экземпляра в
InitMainWindow - это все, что требуется для определения нового
типа основного окна для TMyProgram. Объект приложения вызывает
методы для создания интерфейсного элемента окна (Create) и вывода
его на экран (Show). Вам почти никогда не потребуется использовать эти
методы непосредственно. Обычно они вызываются при вызове
метода MakeWindow объекта приложения.Реакция на сообщения
type
TStepWindow = object(TWindow)
procedure WMLButtonDown(var Msg: TMessage); virtual
vm_First + wm_LButtonDown;
end;
    Примечание: Все программы и модули, переопределяющие
методы ответа на сообщение, должны использовать WinTypes.
procedure TStepWindow.WMLButtonDown(var Msg: TMessage);
begin
MessageBox(HWindow, 'Вы нажали левую кнопку мыши',
'Диспетчеризуемое сообщение', mb_OK);
end;
    Примечание: Программы, которые вызывают MessageBox или
другие функции API Windows, должны использовать модуль WinProcs.
Рис. 1.2 Программа Steps реагирует на пользовательское событие.Завершение прикладной программы