ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 3

Глава 2. Шаг за шагом по Windows
Поскольку Вы уже кратко ознакомились с библиотекой ObjectWindows, вы уже вполне готовы начать построение некоторых простых программ ObjectWindows.  В процессе работы с материалом последующих глав вы будете разрабатывать графическую диалоговую программу д
ля Windows, снабженную меню, возможности записи и загрузки файлов, рисованием текста и изображений и даже простой системой подсказок. По ходу работы вы ознакомитесь с основными принципами разработки приложений Windows. такими как обработка сообщений, упр
авление взаимоотношениями между родительскими и дочерними окнами и автоматической перерисовкой графики.
Наш путь состоит из десяти шагов.
- Шаг 1: Создание приложения
- Шаг 2: Определение типа объекта головного окна
- Шаг 3: Рисование текста в окне
- Шаг 4: Рисование линий в окне
- Шаг 5: Изменение толщины линий
- Шаг 6: Раскраска ваших окон
- Шаг 7: Добавление меню
- Шаг 8: Добавление всплывающих окон и блоков диалога
- Шаг 9: Сохранение изображения в файле
- Шаг 10: Добавление управления в окно и использование элементов
Исходный код приложения в различных стадиях разработки представлен  дистрибутивных дискетах. Соответствующие файлы носят имена STEP1.PAS, STEP2.PAS и т.д. согласно шагам, излагаемым в данном руководстве.
На Рис.2.1 показано приложение, которое будет создано в результате нашей работы.
Рис.2.1. Полное приложение ObjectWindows
Шаг 1: Простое приложение Windows
Следует начать разработку вашего приложения с написания скелета приложения ObjectWindows, которое мы назовем MyProgram. Эта программа, расположенная в файле STEP1.PAS, может послужить отправной точкой для написания вами всех программ в ObjectWindows. MyP
rogram будет создавать головное окно приложения.
Требования приложения
Все программы Windows имеют головное окно, которое появляется после запуска программы пользователем. Пользователь прекращает выполнение приложения, закрывая головное окно. В приложении ObjectWindows головное окно является объектом окна. Объект приложения
 является владельцем этого объекта и он отвечает за создание и отображение головного окна, обработку сообщений Windows и прекращение работы приложения. Объект приложения действует как суррогат самого приложения. Тем же способом ObjectWindows обеспечивает
 окно, диалог и другие типы объектов, укрывая детали программирования в Windows.
Каждая программа ObjectWindows должна определять новый тип приложения, который отличается от поставляемого типа, TApplication. В MyProgram этот тип называется TMyApplication. Приведем головной блок MyProgramm:
var
 MyApp: TMyApplication;
begin
 MyApp.Init('MyProgram');
 MyApp.Run;
 MyApp.Done;
end.
Init является конструктором для TMyApplication и создает новый объект приложения MyApp. Кроме того, он устанавливает имя приложения (в поле объекта) 'MyProgram'. Init также создает и показывает головное меню приложения. Run задает последовательность вызо
вов методов, которые определяют действие нового приложения Windows. Done является деструктором для TMyApplication.
Определение типа приложения
Ваше приложение должно порождать новый тип из стандартного типа ObjectWindows - TApplication (или от некоторого производного от TApplication типа). Этот новый тип должен перекрывать по крайней мере один унаследованный метод, InitMainWindow. TApplication.
InitMainWindow является абстрактным методом, который ObjectWindows вызывает для установки головного окна программы. Каждое приложение ObjectWindows должно конструировать свое собственное головное окно, чтобы носить какую-нибудь смысловую нагрузку.
Приведем определение типа TMyApplication:
TMyApplication=object(TApplication)
 procedure InitMainWindow; virtual;
end;
InitMainWindow отвечает за конструирование объекта окна, который будет служить головным окном приложения. Этот объект головного окна хранится в поле объекта MainWindow. Объект приложения владеет объектом головного окна, но между ними нет иерархии. Эти от
ношения собственности называются компоновкой экземпляров.
procedure TMyApplication.InitMainWindow;
begin
 MainWindow:=New(PWindow, Init(nil,
  'Sample ObjectWindows Program'));
end;
Вы обычно будете модифицировать вышеизложенный метод для задания нового типа головного окна. Предлагаемый метод использует экземпляр объекта TWindow, который является окном типа ObjectWindows и определяет окно самого общего типа. На Шаге 2 он будет замен
ен на более интересный тип окна. На Рис.2.2 показано, как будет выглядеть MyProgram.
Рис.2.2. Ваша первая программа ObjectWindows, MyProgram
Для написания программы ObjectWindows нужно использовать по крайней мере элемент WObjects. Более сложным приложениям потребуется использование дополнительных элементов. Например, любая программа, которая делает непосредственные вызовы Windows API, должна
 включать элементы WinProcs и WinTypes.
На данном этапе MyProgram не делает ничего, кроме вывода на экран пустого окна, которое можно сдвигать, увеличить или уменьшить его размер и закрыть. Приведем полный листинг программы MyProgram на данном этапе (это файл STEP1.PAS):
program MyProgram;
uses WObjects;
type
 TMyApplication=object(TApplication)
  procedure InitMainWindow; virtual;
 end;
procedure TMyApplication.InitMainWindow;
begin
 MainWindow:=New(PWindow, Init(nil,
  'Sample ObjectWindows Program'));
end;
var
 MyApp: TMyApplication;
begin
 MyApp.Init('MyProgram');
 MyApp.Run;
 MyApp.Done;
end.
Шаг 2: Основной тип объекта окна
Созданная на Шаге 1 программа состоит из двух объектов: объект приложения и объект окна. Объект приложения, MyApp, является экземпляром типа TMyApplication, который является производным от типа TApplication. Объект окна, который хранится в поле MainWindo
w объекта приложения, является экземпляром TWindow, окном общего типа ObjectWindows. Во всех программах, кроме наипростейших, вам нужно определить ваш собственный тип окна для головного окна, описывающий специфическое для данного приложения поведение. В 
данном разделе мы привнесем жизнь в объект головного окна, определяя более специализированный тип окна, производный от TWindow.
Что такое объект окна ?
На Шаге 1 вы видели, что объект приложения обладает стандартным поведением приложения Windows, включая конструирование головного окна. Данное поведение характеризуется отображением на экране, изменение размеров и закрытие, реагирование на задаваемые поль
зователем события (нажатие кнопок, протягивание и выбор вариантов меню), вывод управления (блоки списков и клавиши). Тип TWindow и сопутствующий ему TWindowsObjectсоздают основные методы и поля объекта для такого поведения. Для того, чтобы ваши программы
 были более полезными и интересными, вам придется создавать новые типы окон, производные от TWindow. Новый тип будет наследовать методы и поля TWindow, и иметь некоторые собственные. Т.о. объектно-ориентированный подход предостережет вас от "повторного и
зобретения окна".
Регуляторы
Все объекты окна имеют по крайней мере три поля: HWindow, Parent и ChieldList. Как уже было отмечено в Главе 1, HWindow содержит регулятор окна. Регулятор, это номер ID, который связывает интерфейс объекта, такого как окно, блок диалога или объект управл
ения с соответствующим элементом интерфейса.
Т.о. HWindow содержит целую величину, которая идентифицирует соответствующий элемент интерфейса. Это очень похоже на номерок в раздевалке. Для того, чтобы получить пальто, вы должны предъявить номерок, аналогичным образом демонстрируется регулятор для по
лучения доступа к окну. Во многих случаях при работе с объектами окна вам не придется непосредственно манипулировать регулятором окна. Однако, это необходимо при непосредственном вызове функций Windows. Например, для вызова блока сообщения, как вы сами с
делаете в данном разделе, нужно вызвать функцию MessageBox. MessageBox ввести параметр, идентифицирующий родительское окно блока сообщения. Вы укажете головное окно, регулятор которого хранится в поле объекта HWindow:
     MessageBox(MainWindow^.HWindow, 'Do you want to save ?',
     'File has changed', mb_YesNo or mb_IconQuestion);
Родители и дети
Большинство окон не существуют независимо от других: они должны соединяться друг с другом, чтобы действовать сообща. Например, когда вы прекращаете выполнение приложения, оно должно иметь некоторый способ очистки всех окон, за которые оно отвечает. В общ
ем случае, Windows обрабатывает эту ситуацию связывая окна отношениями родителей и детей. Родительское окно отвечает за своих детей. ObjectWindows предоставляет поля для каждого объекта окна для учета его родителей и произвольного числа детей.
Поле Parent объект окна для родительского окна. Родитель не в том смысле, что это предшествующий тип, а это скорее окно-владелец. Родительские отношения окон рассматриваются на Шаге 8.
Третье поле объекта окна, ChildList, содержит связанный список дочерних окон, если они есть. Вы добавите дочернее окно к вашей программе на Шаге 8.
Создание нового типа окна
Сейчас у нас уже есть некоторая информация относительно того, что хранит объект окна и мы можем определить новый тип окна, производный от типа TWindow, для его использования в качестве головного окна в MyProgram. Сначала изменим определение типа для зада
ния нового типа, TMyWindow. Кроме того, нужно определить указатель на этот тип, PMyWindow, Который будет очень полезен при инициализации TMyWindow.
type
 PMyWindow=^TMyWindow;
 TMyWindow=object(TWindow)
end;
Затем внесем изменения в TMyApplication.InitMainWindow таким образом, чтобы она вместо TWindow создавала TMyWindow в качестве головного окна.
procedure TMyApplication.InitMainWindow;
begin
 MainWindow:=New(PMyWindow, Init(nil,
  'Sample ObjectWindows Program'));
end;
Определение нового типа и установка и инициирование его в InitMainWindow это все, что требуется для определения нового типа головного окна TMyProgram. Объект приложения вызывает методы для создания элемента интерфейса окна (Create) и вывода его на экран 
 (Show). Вам почти никогда не придется использовать эти методы непосредственно. Обычно они вызываются при вызове метода объекта приложения MakeWindow. MakeWindow рассматривается в Главе 10, "Объекты окна".
Однако, TMyWindow не определяет никакого нового поведения, кроме унаследованного от TWindow и TWindowObject. Другими словами, программа MyProgram не стала более интересной. В следующем разделе вы добавите ей некоторые новые черты поведения.
Реакция на сообщения
Самый быстрый способ заставить объект окна приносить какую-нибудь пользу это научить его надлежащим образом реагировать на сообщения  Windows. Например, когда пользователь нажимает левую кнопку на мыши в головном окне MyProgram, соответствующий объект ок
на принимает сообщение wm_LButtonDown от Windows. Это говорит объекту окна, что пользователь нажал кнопку на мыши. Кроме того, передаются координаты точки, в которой произошло нажатие. Эта информация будет использоваться на Шаге 6 данного учебного руково
дства.
Аналогично, когда пользователь нажимает левую кнопку на мыши в головном окне MyProgram, соответствующий объект окна принимает сообщение wm_RButtonDown от Windows. Наш следующий шаг состоит в том, чтобы научить головное окно, экземпляр TMyWindow, реагиров
ать на эти сообщения и делать что-либо полезное.
Для интерпретации и реакции сообщений Windows нужно определить свой метод для каждого типа входящего сообщения, которое вы хотите обработать. Такие методы называются методами реакции на сообщения. Для отметки в качестве метода реакции заголовка определен
ия метода будет добавляться расширение, которое является идентификатором сообщения, на которое нужно отреагировать. Например, определяемый ниже метод будет реагировать на все сообщения wm_LButtonDown:
TMyWindow=object(TWindow)
  procedure WMLButtonDown(var Msg:TMessage);
   virtual wm_First+wm_LButtonDown;
end;
Msg это запись TMessage, которая хранит информацию о координатах точки, в которой произошло нажатие кнопки на мыши. Аргумент Msg будет рассмотрен позднее на Шаге 3.
В данный момент давайте определим метод реакции, который будет состоять только в том, что будет появляться блок сообщения о том, что была нажата кнопка на мыши. Позднее будет добавлена некоторая более продуктивная реакция. Приведем определение метода реа
кции на нажатие левой кнопки на мыши:
procedure TMyWindow.WLMButtonDown(var Msg: TMessage);
begin
 MessageBox(HWindow, 'You have pressed the left mouse button',
  'Message Dispatched', mb_OK);
end;
Рис.2.3. Реакция MyProgram на совершенное пользователем событие
Полный исходный код данного шага приведен в конце данной главы.
Прекращение выполнения приложения
Созданная здесь программа закрывается, когда пользователь сделает двойное нажатие кнопки на мыши в блоке меню управления ее головного окна. Это маленький квадрат в левом верхнем углу. После этого окно и приложение немедленно закрывается. подобное поведен
ие очень хорошо для простых программ, но может оказать недостаточно удобным для более сложных. 
Например, заканчиваете ли вы приложение без сохранения результатов проделанной работы ? Хорошо разработанное приложение при своем завершении должно сделать запрос пользователю на сохранение результатов работы, если это еще не было сделано. Такое стереоти
п поведения очень просто добавить к вашим приложениям ObjectWindows. Возьмем MyProgram и добавим ей способность двойной проверки запроса пользователя на прекращение работы. 
При попытке пользователя закрыть свое приложение ObjectWindows для вашего типа приложения вызывается виртуальный метод CanClose. CanClose это Булева функция, которая указывает, действительно ли (True) нужно закрыть приложение. По умолчанию метод CanClose
 наследуется из вызова TApplication метода CanClose объекта головного окна. В большинстве случаев именно объект головного окна решает, действительно ли нужно закрыть приложение. 
Ваш тип головного окна,TMyWindow, наследует метод CanClose из TWindowsObject, который вызывает метод CanClose для каждого из его дочерних окон, если они есть. Если нет дочерних окон (как в данном случае), то CanClose просто возвращает True. Для изменения
 поведения при закрытии приложения нужно переопределить метод CanClose типа объекта головного окна:
function TMyWindow.CanClose: Boolean; 
var Reply: Integer;
begin
 CanClose:=True;
 Reply:=MessageBox(HWindow, 'Do you want to save ?',
  'File has changed', mb_YesNo or mb_IconQuestion);
 if Reply=id_Yes then CanClose:=False;
end;
Теперь при попытке пользователя закрыть MyProgram они увидят блок сообщения с запросом "Do you want to save ?" (Хотите сохранить результаты ?). Нажатие кнопки Yes (Да) возвращает False и предохраняет головное окно и приложение от закрытия. Нажатие кнопки
 No (Нет) возвращает True и выполнение приложения заканчивается. В Части 4 этот блок сообщения приобретет некоторый смысл. На Рис.2.4 показана модифицированная программа MyProgram.
Рис.2.4. MyProgram с модифицированным поведением своего закрытия
Приведем полный код программы MyProgram на данном этапе (это файл    STEP2.PAS):
program MyProgram;
uses WinTypes, WinProc, WObjects;
type
 TMyApplication=object(TApplication)
  procedure InitMainWindow; virtual;
 end;
type
 PMyWindow=^TMyWindow;
 TMyWindow=object(TWindow)
  function CanClose: Boolean; virtual;
  procedure WMLButtonDown(var Msg:TMessage);
   virtual wm_First+wm_LButtonDown;
  procedure WMRButtonDown(var Msg:TMessage);
   virtual wm_First+wm_RButtonDown;
var
 Reply: Integer;
begin
 CanClose:=True;
 Reply:=MessageBox(HWindow, 'Do you want to save ?',
  'File has changed', mb_YesNo or mb_IconQuestion);
 if Reply=id_Yes then CanClose:=False;
end;
procedure TMyWindow.WLMButtonDown(var Msg: TMessage);
begin
 MessageBox(HWindow, 'You have pressed the left mouse button',
  'Message Dispatched', mb_OK);
end;
procedure TMyWindow.WMRButtonDown(var Msg: TMessage);
begin
 MessageBox(HWindow, 'You have pressed the right mouse button',
  'Message Dispatched', mb_OK);
end;
procedure TMyApplication.InitMainWindow;
begin
 MainWindow:=New(PMyWindow, Init(nil,
  'Sample ObjectWindows Program'));
end;
var
 MyApp: TMyApplication;
begin
 MyApp.Init('MyProgram');
 MyApp.Run;
 MyApp.Done;
end.


Яндекс цитирования