Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Win32_f.doc
Скачиваний:
9
Добавлен:
03.05.2019
Размер:
899.07 Кб
Скачать

230 ____Глава 26

нем Ps), используемую системой Windows при перерисовке изображения (см. гл. 8). Функций-членов в классе TPaintDC всего две: конструктор TPaintDC() и деструктор ~TPaintDC(). Как показано на рис. 26.2, в конструкторе вызывается функция API Windows BeginPaint(), которая заполняет структуру Ps и воз­вращает контекст устройства; в деструкторе вызывается функция API Windows EndPaint(), освобождаю­щая контекст устройства. Таким образом, при создании объекта класса TPaintDC автоматически выпол­няются необходимые инициализирующие действия, а при его уничтожении - необходимые завершаю­щие действия. Стоит еще отметить, что в деструктор ~TPaintDC() входит также вызов функции Restore-Objects(), выполняющей выбор в контекст устройства исходных инструментов. Таким образом, в OWL-программе после окончания работы с созданными и выбранными в контекст устройств инструментами, нет необходимости выполнять относительно громоздкую процедуру выбора назад в контекст всех ис­ходных дескрипторов, так это действие автоматически выполняется в деструкторе класса.

Поступление в окно приложения сообщения WM_PAINT приводит к вызову защищенной функции класса TWindow EvPaint(). Поскольку сообщение WM_PAINT приходит в наше окно, с которым ассо­циируется объект MyWin (являющийся потомком класса TWindow и наследующий его открытые и за­щищенные члены), то функция EvPaint() вызывается именно для этого объекта. Определение функции EvPaint() (которое можно найти в файле SOURCE\OWL\WINDOW.CPP), за вычетом некоторых несуще­ственных пока деталей, выглядит следующим образом:

void TWindow::EvPaint(){ TPaintDC dc(*this);

TRect& rect=*(TRect*)&dc.Ps.rcPaint; Paint(dc,dc.Ps.fErase,rect);

}

В первом предложении вызывается конструктор класса TPaintDC, который создает объект этого класса с именем dc. Имя этого объекта используется в дальнейших предложениях приведенного фраг­мента, а также и в тексте нашей программы. Прототип конструктора класса TPaintDC имеет следующий вид:

TPaintDC (HWND);

В качестве аргумента конструктора выступает дескриптор окна типа HWND. Однако в функции EvPaint() в качестве фактического аргумента конструктора использовано обозначение *this, что означает указатель на текущий объект со снятой ссылкой, т.е. сам текущий объект (этот объект в нашей програм­ме не имеет имени, так как создан не по имени, а с помощью указателя MyWin). Каким образом целый объект *MyWin преобразуется в конкретное данное типа HWND? Это делается с помощью оператора преобразования типа, включенного в класс TWindow, который в OWL 2.5 (пакет Borland C++ 4.5) вы­глядит следующим образом:

TWindow::operator HWND() const {return HWindow;}

Как было показано в гл. 22, операторы такого рода позволяют преобразовывать пользовательские классы в скалярные данные базовых типов; в данном случае задаются правила преобразования класса TWindow в скалярную переменную HWindow типа HWND. Конструктор TPaintDC требует в качестве ар­гумента переменную типа HWND, однако в функции EvPaint() он вызывается с указанием параметра ти­па "объект класса TWindow". Следовательно, компилятор должен преобразовать объект TWindow в пе­ременную типа HWND. Правила такого преобразования, задаваемые оператором operator, требуют под­становки вместо объекта класса TWindow данного-члена того же класса HWindow. Таким образом, кон­структор TPaintDC получает в качестве параметра данное HWindow, представляющее собой дескриптор окна, которое он затем использует при вызове функции BeginPaint().

В OWL 5.0 (пакет Borland C++ 5.0) описанная процедура выглядит сложнее, хотя ее смысл остается в точности тем же. Отличие заключается в том, что в классе TWindow оператором typedef вводится новый тип данных THandle, в точности эквивалентный HWND: typedef HWND THandle;

и, соответственно, переменная класса, представляющая дескриптор окна (она здесь имеет имя не HWin­dow, a Handle), объявлена типа THandle:

THandle Handle;

Оператор преобразования типа также написан для типа THandle: TWindow::operator THandle() const {return GetHandle();}

Функция GetHandle() того же класса возвращает дескриптор окна Handle: TWindow::THandle TWindow::GetHandle() const {return Handle;}

В итоге конструктор TPaintDC получает в качестве параметра дескриптор окна Handle, который за­тем передается в функцию BeginPaint().

Вернемся, однако, к обсуждению функции EvPaint(). Во втором предложении этой функции TRect& rect=*(TRect*)&dc.Ps.rcPaint;

Обработка сообщения WM_PAINT и интерфейс GDI 231

создается ссылочная переменная rect класса TRect. Эта переменная описывает прямоугольную область (в данном случае - область вырезки изображения) по ее четырем координатам. Как известно, область вы­резки передается Windows в элемент rcPaint структуры PAINTSTRUCT, однако она имеет там тип RECT. Поскольку переменная rcPaint является элементом структурного объекта Ps типа PAINTSTRUCT, a Ps является данным-членом объекта dc (созданного конструктором), полное имя области вырезки будет dc.Ps.rcPaint. В приведенном выше предложении образуется адрес этой переменной (&dc.Ps.rcPaint), с помощью префикса преобразования типа (TRect*) преобразуется в указатель на класс TRect, затем с него снимается ссылка (знак *) и полученное значение присваивается ссылочной переменной rect. В итоге в rect поступает область вырезки.

В последнем предложении функции EvPaint()

Paint(dc,dc.Ps.fErase,rect);

вызывается функция TWmdow::Paint() с передачей ей трех параметров: образованного ранее объекта dc класса TPaintDC, члена fErase структуры Ps и области вырезки rect. Как уже отмечалось выше, функция Paint() является заглушкой, которую необходимо переопределять в производных классах, при этом за­мещающая ее функция производного класса получает все три описанные выше параметра и может с ни­ми работать.

Заметим, что в прототипе функции Paint

virtual void Paint(TDC& dc, bool erase, TRect& rect);

первый аргумент указан типа TDC, а мы присваиваем ему значение типа TPaintDC. Поскольку, однако, класс TPaintDC является производным от TDC, такое преобразование указателей (и ссылочных перемен­ных) является допустимым (см. гл. 24). Правда, при этом преобразовании объект dc усекается до содер­жимого базового класса TDC и из него исключаются члены, добавленные классом TPaintDC, конкретно, структура Ps и дескриптор окна Wnd, которые мы уже не можем использовать в функции Paint(). Види­мо, разработчики полагали, что эти данные не понадобятся прикладной программе. Область же вырезки, которая может программе потребоваться, передается в функцию Paint() через параметр rect. Передается также и флаг стирания фона окна, который обычно имеет нулевое значение, задающее автоматическое перерисовывание фона окна программами Windows.

Итак, при поступлении в наше окно сообщения WM_PAINT, автоматически создается объект класса TPaintDC с конкретным именем dc, через который мы можем получить доступ ко всему набору графиче­ских функций класса TDC, и выполняется вызов функции API Windows BeginPaint(), которая заполняет структуру Ps. Наша задача теперь сводится к вызову любых требуемых функций GDI для объекта dc. В примере 26-1 для объекта dc вызывается единственная функция TextOut() (инкапсулированная в OWL) для вывода строки текста:

dc.TextOut(10,10,"Строка текста");//Вывод строки текста

В дальнейших примерах будут проиллюстрированы приемы работы с другими функциями GDI.

Как уже отмечалось, при выходе из функции нам нет необходимости заботиться об освобождении контекста устройства (функция API Windows EndPaint()), так как эту работу берет на себя класс TPaintDC.

Вывод в окно геометрических фигур

На рис. 26.3. приведен результат работы приложения, рас­сматриваемого в этом разделе.

//Пример 26-2. Вывод геометрических фигур

//Файл 26-2.срр

#include <owl\framewin.h>

/*Отображаемые на графике даяние*/

int data[10]={0,20,15,36,50,45,50,70,85,100); /*Константы, описывающие размера изображения*/

const radius=4;//Радиус точек графика

const dx=2Q;//Шаг по X

const margins=10;//Поля графика

const X=dx*9; // Ширина графика из 10 точек

const Y=100;//Высота графика

const XBorder=X+2*margins;/7Высота рамки вокруг графика const YBorder=Y+2*margins;//Ширина рамки вокруг графика /*Объекты классов положения и размеров*/

TSize size(radius*2,radius*2);//Квадрат для рисования точек графика TPoint X0Y0(30,10);//Верхний левый угол рамки относительно окна приложения TPoint XmYm=X0Y0.OffsetBy(XBorder,YBorder);//Правый нижний угол рамки TRect border(X0Y0,XmYm);//Прямоугольник рамки TRect graph=border.InflatedBy(-margins,-margins);//Прямоугольник графика

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]