- •Часть IV
- •Глава 25
- •224 Глава 25
- •226 Глава 25
- •Глава 26
- •230 ____Глава 26
- •232 Глава 26
- •234 Глава 26
- •236 Глава 26
- •238 Глава 26
- •240 Глава 26
- •242 Глава 26
- •Глава 27
- •Virtual void InitMainWindow();//Замещаем функцию InitMainWindow
- •246 Глава 27
- •248 Глава 27
- •250 Глава 27
- •252 . Глава27
- •Глава 28 Диалоговые окна
- •256 Глава 28
- •258 Глава 28
- •260 Глава 28
- •262 Глава 28
- •264 Глава 28
- •266 Глава 28
- •268 Глава 28
- •Глава 29
- •270 Глава 29
- •272 Глава 29
- •274 Глава 29
- •276 Глава 29
- •278 Глава 29
- •280 Глава 29
- •282 Глава 29
Глава 26
Обработка сообщения WM_PAINT и интерфейс графических устройств GDI
Исходный текст программы, выводящей в окно строку символов
В предыдущей главе была рассмотрена структура простейшего OWL-приложения с главным окном. Мы даже научились изменять размеры и цвет окна. Однако это окно было пусто - для того, чтобы в него что-то вывести, надо обрабатывать сообщение WM_PAINT и использовать инструменты графического интерфейса GDI. Принципы обработки сообщений Windows в OWL-прштожениях будут описаны в следующей главе; здесь же мы рассмотрим только работу с сообщением WM_PAINT и вывод на экран изображений с помощью функций GDI.
На рис. 26.1. приведен результат работы первого приложения, рассматриваемого в этой главе.
Рис. 26.1. Вывод на экран строки текста с помощью функции GDI.
//Приложение 26-1. Вывод текста в окно
//Файл 26-1.срр
#include <owl\framewin.h>
/*Класс приложения, производная от Tapplication*/
class MyApp:public TApplication{
public:
virtual void InitMainWindow(void);//Замещаем функцию InitMainWindow };
/*Класс главного окна, производный от TFrameWindow (ради Paint) */ class MyWindow:public TFrameWindow{ public:
MyWindow(TWindow*parent,const char far* title):TFrameWindow(parent,title){ Attr.X=20;Attr.Y=20;//Задаем координаты окна Attr.W=200;Attr.H=60;//Задаем размеры окна }
void Paint(TDC&,bool,TRect&);//Замещаем функцию Paint()класса TWindow };
/*Замещенная функция InitMainWindow ()*/ void MyApp::InitMainWindow(void){
MyWindow* myWin=new MyWindow(0,"Программа 26-1");
SetMainWindow(myWin);
}
/*Замещенная функция Paint ()*/ void MyWindow::Paint(TDC&dc,bool,TRect&){//Определяем нашу функцию Paint О
dc.TextOut(10,10,"Строка текста");//Вывод строки текста
} /*Главная функция приложения OwlMain*/
int OwlMain(int,char*[]){
MyApp* myApp=new MyApp;
return myApp->Run(); }
Обработка сообщения WM_PAINT и интерфейс GDI 229
Обработка сообщения WM_PAINT
Сравнивая примеры 25-1 и 26-1, легко заметить, что они различаются всего несколькими строками. К числу несущественных отличий относится изъятие из конструктора класса главного окна MyWindow строки задания цвета фона окна, в результате чего окно приложения будет иметь цвет по умолчанию, т.е. белый. Более принципиальное отличие заключается в том, что в классе MyWindow замещена открытая виртуальная функция класса TWindow Paint(), которая перешла по наследству сначала в производный от TWindow класс TFrameWindow, а оттуда в прикладной класс MyWindow. Эта функция вызывается программами OWL в ответ на приход в окно приложения сообщения WM_PAINT. Исходная функция Paint(), входящая в класс TWindow, является функцией-заглушкой: в ее определении нет не единой строки. Заместив ее в производном от TWindow классе функцией с разумным содержимым, мы получаем возможность обрабатывать в нашей программе сообщения WM_PAINT, поступающие (в данном случае) в главное окно приложения. В примере 26-1 обработка заключается в выводе в окно с помощью функции TextOut() короткой строки текста; в следующих примерах будут продемонстрированы другие средства графического интерфейса.
Функция TextOut() принадлежит классу TDC и вызывается для объекта этого класса dc (откуда взялся этот объект, будет объяснено ниже). Эта функция совпадает по наименованию и смыслу с аналогичной функцией Windows API, хотя отличается от последней набором аргументов (см. для сравнения пример 8.1 из гл. 8). В таком случае говорят, что функция OWL инкапсулирует аналогичную функцию API. Практически все основные функции API Windows инкапсулированы в библиотеке OWL, хотя способ их вызова и состав аргументов, естественно, различаются. Иногда оказывается, что требуемая функция OWL недоступна в конкретном месте программы (потому что принадлежит другому классу и объявлена в нем защищенной или даже закрытой); тогда приходится обращаться к соответствующей функции Windows API. Примеры такого рода будут приведены в дальнейшем.
"Отлавливание" требуемого сообщения в прикладной программе просто путем вызова функции с тем же именем характерна только для сообщения WM_PAINT. Остальные сообщения следует обслуживать по другим, более сложным правилам, создавая в программе таблицу откликов на сообщения и связывая эту таблицу с набором прикладных функций обработки сообщений; эти процедуры будут подробно рассмотрены в последующих главах. Сообщение же WM_PAINT, учитывая его важность, частично обслуживается внутри класса TWindow, где имеется своя таблица откликов; программисту предоставляется функция-заглушка, и на его долю остается только написать свою функцию с именем Paint().
Рассмотрим немного подробнее процедуру обслуживания сообщений WM_PAINT классом TWindow. Это поможет нам разобраться в смысле аргументов функции Paint() и правилах составления текста замещающей функции.
Как было показано в гл. 8, важнейшим понятием GDI является контекст устройства, содержимого которого в каждый момент определяет характеристики всех доступных инструментов рисования. В действительности в Windows используется не один, а целый ряд контекстов устройств, предоставляющих возможность рисовать в рабочей области окна, во всем окне приложения, на рабочем столе, на всем экране и т.д. Наиболее общие свойства контекстов устройств описаны в классе TDC, являющемся базовым для подклассов, определяющих свойства упомянутых выше контекстов. Из этих производных подклассов нас пока будет интересовать только класс TPaintDC, с экземпляром которого dc мы сталкиваемся в нашей программе. С другой стороны, сам класс TDC является производным от базового для всей графической системы (а не только для контекстов устройств) класса TGdiBase. Эти три класса образуют структуру, изображенную на рис. 26.2.
Рассмотрим некоторые из членов приведенной иерархии классов.
В базовый класс TGdiBase входит дескриптор контекста устройства Handle. Этот дескриптор имеет обобщенный тип HANDLE, который затем преобразуется в более привычный нам тип контекста устройства НDС.
Класс TDC, являющийся базовым для целого ряда классов, описывающих различные контексты устройств (TPaintDC, TWin-dowDC, TClientDC и др.), включает дескрипторы исходных графических объектов (ин-
струментов рисования) OrgBrush, OrgPen, OrgFont и OrgPalette, а также большое количество (около 200) графических функций, обеспечивающих вывод на экран текстов, фигур и других изображений, создание, выбор и настройку инструментов рисования,- получение и изменение режимов работы графической системы и т.д. Большинство этих функций инкапсулируют соответствующие функции API Windows.
Очень небольшой по объему класс TPaintDC содержит в качестве данных-членов дескриптор окна типа HWND (данное с именем Wnd) и хорошо известную нам структуру PAINTSTRUCT (данное с име-