🗊Презентация Интерфейс графических устройств GDI

Нажмите для полного просмотра!
Интерфейс графических устройств GDI, слайд №1Интерфейс графических устройств GDI, слайд №2Интерфейс графических устройств GDI, слайд №3Интерфейс графических устройств GDI, слайд №4Интерфейс графических устройств GDI, слайд №5Интерфейс графических устройств GDI, слайд №6Интерфейс графических устройств GDI, слайд №7Интерфейс графических устройств GDI, слайд №8Интерфейс графических устройств GDI, слайд №9Интерфейс графических устройств GDI, слайд №10Интерфейс графических устройств GDI, слайд №11Интерфейс графических устройств GDI, слайд №12Интерфейс графических устройств GDI, слайд №13Интерфейс графических устройств GDI, слайд №14Интерфейс графических устройств GDI, слайд №15Интерфейс графических устройств GDI, слайд №16Интерфейс графических устройств GDI, слайд №17Интерфейс графических устройств GDI, слайд №18Интерфейс графических устройств GDI, слайд №19Интерфейс графических устройств GDI, слайд №20Интерфейс графических устройств GDI, слайд №21Интерфейс графических устройств GDI, слайд №22Интерфейс графических устройств GDI, слайд №23Интерфейс графических устройств GDI, слайд №24Интерфейс графических устройств GDI, слайд №25Интерфейс графических устройств GDI, слайд №26Интерфейс графических устройств GDI, слайд №27Интерфейс графических устройств GDI, слайд №28

Содержание

Вы можете ознакомиться и скачать презентацию на тему Интерфейс графических устройств GDI. Доклад-сообщение содержит 28 слайдов. Презентации для любого класса можно скачать бесплатно. Если материал и наш сайт презентаций Mypresentation Вам понравились – поделитесь им с друзьями с помощью социальных кнопок и добавьте в закладки в своем браузере.

Слайды и текст этой презентации


Слайд 1





Интерфейс графических устройств
GDI
Описание слайда:
Интерфейс графических устройств GDI

Слайд 2





Интерфейс графических устройств 
(Graphical Device Interface, GDI)
GDI  представляет собой совокупность программных средств Windows, организующих вывод на различные устройства вывода
на экран, 
на устройства печати
в файлы 
все многообразие графических объектов: 
текстовых строк,
геометрических фигур, 
растровых изображений 
др.
Описание слайда:
Интерфейс графических устройств (Graphical Device Interface, GDI) GDI представляет собой совокупность программных средств Windows, организующих вывод на различные устройства вывода на экран, на устройства печати в файлы все многообразие графических объектов: текстовых строк, геометрических фигур, растровых изображений др.

Слайд 3





GDI предоставляет программисту более двухсот функций для управления режимами вывода и построения на экране требуемых изображений. 
функции для создания инструментов рисования 
цветные кисти и перья, шрифты различных гарнитур; 
функции управления цветами; 
функции получения и задания режимов рисования; 
функции вывода тех или иных объектов и т.д.

Помимо самого вывода изображений, в задачу интерфейса GDI входит наблюдение за границами, в которых осуществляется этот вывод. Так, программа может попытаться вывести на экран очень длинную текстовую строку или другое изображение большого размера. 
Однако GDI отобразит на экране только те части этих объектов, которые попадают внутрь окна приложения. 
В результате приложения никогда не затирают друг друга, сосуществуя в пределах своих окон.
Описание слайда:
GDI предоставляет программисту более двухсот функций для управления режимами вывода и построения на экране требуемых изображений. функции для создания инструментов рисования цветные кисти и перья, шрифты различных гарнитур; функции управления цветами; функции получения и задания режимов рисования; функции вывода тех или иных объектов и т.д. Помимо самого вывода изображений, в задачу интерфейса GDI входит наблюдение за границами, в которых осуществляется этот вывод. Так, программа может попытаться вывести на экран очень длинную текстовую строку или другое изображение большого размера. Однако GDI отобразит на экране только те части этих объектов, которые попадают внутрь окна приложения. В результате приложения никогда не затирают друг друга, сосуществуя в пределах своих окон.

Слайд 4





GDI участвует в организации графической оболочкой многослойного экранного кадра
на экране может быть одновременно изображено несколько окон одного или различных приложений, 
окна верхнего уровня отображаются целиком, а от окон нижних уровней видны только выступающие части. 
Для того чтобы это было возможным, перерисовка каждого окна должна вестись только в пределах видимых в настоящий момент границ.
Для успешного использования графических возможностей Windows в прикладных программах программист должен 
не только знать состав и особенности применения многочисленных функций, связанных с изображением на экране графических объектов (это, кстати, наиболее простая задача), 
но и понимать принципы динамического взаимодействия системы с приложением в процессе организации экранного кадра.
Описание слайда:
GDI участвует в организации графической оболочкой многослойного экранного кадра на экране может быть одновременно изображено несколько окон одного или различных приложений, окна верхнего уровня отображаются целиком, а от окон нижних уровней видны только выступающие части. Для того чтобы это было возможным, перерисовка каждого окна должна вестись только в пределах видимых в настоящий момент границ. Для успешного использования графических возможностей Windows в прикладных программах программист должен не только знать состав и особенности применения многочисленных функций, связанных с изображением на экране графических объектов (это, кстати, наиболее простая задача), но и понимать принципы динамического взаимодействия системы с приложением в процессе организации экранного кадра.

Слайд 5





Одним из наиболее важных системных средств является сообщение WM_PAINT 
//Программа Сообщение WM PAINT 

/*0ператоры препроцессора*/

#include <windows.h>	//Два файла с определениями, макросами 
#include <windowsx.h>	//и прототипами функций Windows
Описание слайда:
Одним из наиболее важных системных средств является сообщение WM_PAINT //Программа Сообщение WM PAINT /*0ператоры препроцессора*/ #include <windows.h> //Два файла с определениями, макросами #include <windowsx.h> //и прототипами функций Windows

Слайд 6





/*Прототипы используемых в программе функций пользователя*/


LRESULT CALLBACK WndProc(HWND,UINT, WPARAM, LPARAM); //Оконная функция
void OnPaint(HWND);		//Прототип функции OnPaint 
void OnDestroy(HWND);		//Прототип функции OnDestroy
Описание слайда:
/*Прототипы используемых в программе функций пользователя*/ LRESULT CALLBACK WndProc(HWND,UINT, WPARAM, LPARAM); //Оконная функция void OnPaint(HWND); //Прототип функции OnPaint void OnDestroy(HWND); //Прототип функции OnDestroy

Слайд 7





/*  Главная функция WinMain*/

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
	char szClassName[]="MainWindow";		//Произвольное имя класса главного окна 
	char szTitle[]="Программа GDI_1";		//Произвольный заголовок окна 
	MSG Msg;					//Структура Msg типа MSG для 						временного хранения сообщений Windows 
	WNDCLASS wc;				//Структура wc типа WNDCLASS для 						задания характеристик окна
Описание слайда:
/* Главная функция WinMain*/ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) { char szClassName[]="MainWindow"; //Произвольное имя класса главного окна char szTitle[]="Программа GDI_1"; //Произвольный заголовок окна MSG Msg; //Структура Msg типа MSG для временного хранения сообщений Windows WNDCLASS wc; //Структура wc типа WNDCLASS для задания характеристик окна

Слайд 8





/* Регистрация класс главного окна*/
	
memset (&wc, 0, sizeof (wc) );		//Обнуление всех членов структуры wc
wc.lpfnWndProc=WndProc;		//Определяем оконную процедуру для главного окна
wc.hInstance=hInst;		//Дескриптор приложения 
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);		//Стандартная иконка
wc.hCursor=LoadCursor(NULL,IDC_ARROW);		//Стандартный курсор мыши 
wc.hbrBackground=GetStockBrush(WHITE_BRUSH);	//Белая кисть для фона окна 
wc.lpszClassName=szClassName;			//Класс главного окна 

RegisterClass(&wc);			//Вызов функции Windows регистрации класса окна
Описание слайда:
/* Регистрация класс главного окна*/ memset (&wc, 0, sizeof (wc) ); //Обнуление всех членов структуры wc wc.lpfnWndProc=WndProc; //Определяем оконную процедуру для главного окна wc.hInstance=hInst; //Дескриптор приложения wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); //Стандартная иконка wc.hCursor=LoadCursor(NULL,IDC_ARROW); //Стандартный курсор мыши wc.hbrBackground=GetStockBrush(WHITE_BRUSH); //Белая кисть для фона окна wc.lpszClassName=szClassName; //Класс главного окна RegisterClass(&wc); //Вызов функции Windows регистрации класса окна

Слайд 9





/*Создадим главное окно и сделаем его видимым*/


HWND hwnd=CreateWindow(szClassName,szTitle,//Класс и заголовок окна
	WS_OVERLAPPEDWINDOW,10,10,300,100,//Стиль окна, его координаты и размеры 
	HWND_DESKTOP,NULL,hInst,NULL);	//Родитель, меню, другие параметры

ShowWindow(hwnd,SW_SHOWNORMAL);	//Вызов функции Windows показа окна
Описание слайда:
/*Создадим главное окно и сделаем его видимым*/ HWND hwnd=CreateWindow(szClassName,szTitle,//Класс и заголовок окна WS_OVERLAPPEDWINDOW,10,10,300,100,//Стиль окна, его координаты и размеры HWND_DESKTOP,NULL,hInst,NULL); //Родитель, меню, другие параметры ShowWindow(hwnd,SW_SHOWNORMAL); //Вызов функции Windows показа окна

Слайд 10





/*0рганизуем цикл обработки сообщений*/


while(GetMessage(&Msg,NULL,0,0))	//Цикл обработки сообщении: ждать

	DispatchMessage(&Msg);	//сообщения, записать его в msg и передать WndProc 
return 0;			//После выхода из цикла обработки 
				//сообщений вернуться в Windows
}				//Конец функции WinMain
Описание слайда:
/*0рганизуем цикл обработки сообщений*/ while(GetMessage(&Msg,NULL,0,0)) //Цикл обработки сообщении: ждать DispatchMessage(&Msg); //сообщения, записать его в msg и передать WndProc return 0; //После выхода из цикла обработки //сообщений вернуться в Windows } //Конец функции WinMain

Слайд 11





/*0конная функция главного
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{ 
switch(msg)
	{			//Переход по значению msg - коду сообщения
	HANDLE_MSG(hwnd,WM_PAINT,OnPaint)	;//При поступлении сообщения 							WM_PAINT 
	HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);	//При завершении пользователем 
	default:					//В случае всех остальных сообщений 						Windows обработка их
return(DefWindowProc(hwnd,msg,wParam,lParam));	//по умолчанию 
	}					//Конец оператора switch 
}						//Конец функции WndProc
Описание слайда:
/*0конная функция главного LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch(msg) { //Переход по значению msg - коду сообщения HANDLE_MSG(hwnd,WM_PAINT,OnPaint) ;//При поступлении сообщения WM_PAINT HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy); //При завершении пользователем default: //В случае всех остальных сообщений Windows обработка их return(DefWindowProc(hwnd,msg,wParam,lParam)); //по умолчанию } //Конец оператора switch } //Конец функции WndProc

Слайд 12





/*Функция обработки сообщения WM_DESTROY*/


void OnDestroy(HWND)
{
	PostQuitMessage(0);//Вызов функции Windows завершения приложения
}
Описание слайда:
/*Функция обработки сообщения WM_DESTROY*/ void OnDestroy(HWND) { PostQuitMessage(0);//Вызов функции Windows завершения приложения }

Слайд 13





/*Функция обработки сообщений WM_PAINT*/


void OnPaint(HWND hwnd){
	char szText[]="Строка текста для вывода в главное окно";
	PAINTSTRUCT ps;		//Структура, требуемая для рисования в рабочей области
	HDC hdc=BeginPaint(hwnd,&ps);	//Получение контекста устройства
	TextOut(hdc,5,30,szText,strlen(szText));	//Вывод строки текста с точки 5,30
	EndPaint(hwnd,&ps);			//Освобождение контекста устройства
}					//Конец функции OnPaint()
Описание слайда:
/*Функция обработки сообщений WM_PAINT*/ void OnPaint(HWND hwnd){ char szText[]="Строка текста для вывода в главное окно"; PAINTSTRUCT ps; //Структура, требуемая для рисования в рабочей области HDC hdc=BeginPaint(hwnd,&ps); //Получение контекста устройства TextOut(hdc,5,30,szText,strlen(szText)); //Вывод строки текста с точки 5,30 EndPaint(hwnd,&ps); //Освобождение контекста устройства } //Конец функции OnPaint()

Слайд 14





Функция OnPaint() 
Программный блок обработки сообщений WM_PAINT выделен в функцию OnPaint(). Соответственно в раздел прототипов включен прототип этой функции.

void OnPaint(HWND hwnd){
	char szText[]="Строка текста для вывода в главное окно";
	PAINTSTRUCT ps;		//Структура, требуемая для рисования в рабочей области
	HDC hdc=BeginPaint(hwnd,&ps);	//Получение контекста устройства
	TextOut(hdc,5,30,szText,strlen(szText));	//Вывод строки текста с точки 5,30
	EndPaint(hwnd,&ps);			//Освобождение контекста устройства
}					//Конец функции OnPaint()

Рассмотрим более детально роль сообщения WM_PAINT и процедуру его обработки.
Описание слайда:
Функция OnPaint() Программный блок обработки сообщений WM_PAINT выделен в функцию OnPaint(). Соответственно в раздел прототипов включен прототип этой функции. void OnPaint(HWND hwnd){ char szText[]="Строка текста для вывода в главное окно"; PAINTSTRUCT ps; //Структура, требуемая для рисования в рабочей области HDC hdc=BeginPaint(hwnd,&ps); //Получение контекста устройства TextOut(hdc,5,30,szText,strlen(szText)); //Вывод строки текста с точки 5,30 EndPaint(hwnd,&ps); //Освобождение контекста устройства } //Конец функции OnPaint() Рассмотрим более детально роль сообщения WM_PAINT и процедуру его обработки.

Слайд 15





Обработка сообщений WM_PAINT

Сообщения WM_PAINT выделяются среди всех остальных тем, что их обработка включается практически в любое приложение Windows, если в нем хоть что-нибудь рисуется на экране. 
Общее правило рисования заключается в том, что вывод в окно приложения любых графических объектов 
текстовых строк, 
геометрических фигур, 
отдельных точек, 
растровых изображений - 
должен выполняться исключительно в процедуре обработки сообщения WM_PAINT. 
Только в этом случае графическое содержимое окна не будет теряться при загораживании данного окна окнами других приложений. 
Каким образом вообще Windows поддерживает содержимое своих многочисленных окон?
Описание слайда:
Обработка сообщений WM_PAINT Сообщения WM_PAINT выделяются среди всех остальных тем, что их обработка включается практически в любое приложение Windows, если в нем хоть что-нибудь рисуется на экране. Общее правило рисования заключается в том, что вывод в окно приложения любых графических объектов текстовых строк, геометрических фигур, отдельных точек, растровых изображений - должен выполняться исключительно в процедуре обработки сообщения WM_PAINT. Только в этом случае графическое содержимое окна не будет теряться при загораживании данного окна окнами других приложений. Каким образом вообще Windows поддерживает содержимое своих многочисленных окон?

Слайд 16





 Выделим несколько типичных ситуаций.

Если мы с помощью мыши или клавиатуры перемещаем окно приложения по экрану, то этот процесс не затрагивает само приложение. 
Копирование содержимого окна по мере его перемещения на новые места экрана обеспечивают системные программы Windows. 
Следовательно, о сохранении содержимого окна в этом случае можно не думать.
Описание слайда:
Выделим несколько типичных ситуаций. Если мы с помощью мыши или клавиатуры перемещаем окно приложения по экрану, то этот процесс не затрагивает само приложение. Копирование содержимого окна по мере его перемещения на новые места экрана обеспечивают системные программы Windows. Следовательно, о сохранении содержимого окна в этом случае можно не думать.

Слайд 17





Сообщение WM_PAINT
Программа в ответ на сообщение WM_PAINT должна сама восстановить все, что должно изображаться в окне. 
Windows сообщает в приложение, какая часть окна требует перерисовки, 
приложение в принципе может перерисовывать только поврежденную часть окна, что заметно сократило бы временные издержки на вывод изображения. 
Однако, такой алгоритм рисования составить слишком сложно, если вообще возможно, и в ответ на сообщение WM_PAINT программа вынуждена заново рисовать все, что должно изображаться в окне.
Описание слайда:
Сообщение WM_PAINT Программа в ответ на сообщение WM_PAINT должна сама восстановить все, что должно изображаться в окне. Windows сообщает в приложение, какая часть окна требует перерисовки, приложение в принципе может перерисовывать только поврежденную часть окна, что заметно сократило бы временные издержки на вывод изображения. Однако, такой алгоритм рисования составить слишком сложно, если вообще возможно, и в ответ на сообщение WM_PAINT программа вынуждена заново рисовать все, что должно изображаться в окне.

Слайд 18





Рабочая область окна 

Главное окно приложения обычно имеет 
заголовок с управляющими кнопками
толстую рамку
линейку меню. 
Все эти элементы окна образуют нерабочую область окна (nonclient area, неклиентская область) и обычно недоступны программе. 
Остальная часть окна, куда программа может выводить что угодно, называется рабочей областью (client area, область клиента)
 Восстановление нерабочей области при любых манипуляциях с окном Windows берет на себя, программа обязана восстанавливать только рабочую область.
Описание слайда:
Рабочая область окна Главное окно приложения обычно имеет заголовок с управляющими кнопками толстую рамку линейку меню. Все эти элементы окна образуют нерабочую область окна (nonclient area, неклиентская область) и обычно недоступны программе. Остальная часть окна, куда программа может выводить что угодно, называется рабочей областью (client area, область клиента) Восстановление нерабочей области при любых манипуляциях с окном Windows берет на себя, программа обязана восстанавливать только рабочую область.

Слайд 19





Контекст устройства.

Обработка сообщения WM_PAINT связана с использованием важнейшего поля данных Windows, называемого контекстом устройства.
Контекст устройства представляет собой системную область памяти, закрепляемую за рабочей областью окна, в которой хранятся текущие значения режимов, связанных с рисованием, а также дескрипторы инструментов рисования - кисти, пера, шрифта и пр. 
Все графические функции GDI используют контекст устройства для определения режима рисования и характеристик применяемых ими инструментов.
Описание слайда:
Контекст устройства. Обработка сообщения WM_PAINT связана с использованием важнейшего поля данных Windows, называемого контекстом устройства. Контекст устройства представляет собой системную область памяти, закрепляемую за рабочей областью окна, в которой хранятся текущие значения режимов, связанных с рисованием, а также дескрипторы инструментов рисования - кисти, пера, шрифта и пр. Все графические функции GDI используют контекст устройства для определения режима рисования и характеристик применяемых ими инструментов.

Слайд 20





Пример
функция вывода линии получает из контекста устройства 
толщину 
цвет пера
 		(через дескриптор пера) которым должна быть нарисована линия; 
функции вывода геометрических фигур, в добавление к характеристикам пера, получают
цвет и 
фактуру кисти 
		для закрашивания (заливки) рисуемых фигур; 
функции вывода текста получают (через дескриптор шрифта) все необходимые характеристики шрифта 
гарнитуру, 
размер, 
цвет, 
насыщенность (жирность) и пр.
Описание слайда:
Пример функция вывода линии получает из контекста устройства толщину цвет пера (через дескриптор пера) которым должна быть нарисована линия; функции вывода геометрических фигур, в добавление к характеристикам пера, получают цвет и фактуру кисти для закрашивания (заливки) рисуемых фигур; функции вывода текста получают (через дескриптор шрифта) все необходимые характеристики шрифта гарнитуру, размер, цвет, насыщенность (жирность) и пр.

Слайд 21





Дескриптор контекста
Контекст устройства становится известен графическим функциям GDI через дескриптор контекста, который для всех этих функций служит первым параметром.


Контекст устройства относится к числу системных ресурсов, количество которых в системе может быть ограничено; 
Работа с такого рода ресурсами всегда протекает одинаково: 
сначала надо получить у системы требуемый ресурс 
закончив работу с ним, вернуть его системе.
Описание слайда:
Дескриптор контекста Контекст устройства становится известен графическим функциям GDI через дескриптор контекста, который для всех этих функций служит первым параметром. Контекст устройства относится к числу системных ресурсов, количество которых в системе может быть ограничено; Работа с такого рода ресурсами всегда протекает одинаково: сначала надо получить у системы требуемый ресурс закончив работу с ним, вернуть его системе.

Слайд 22





Вывод изображения в окно
Таким образом, для того чтобы вывести в окно некоторое изображение, необходимо выполнить следующие действия, последовательность которых, в сущности, определяет алгоритм обработки сообщения WM_PAINT:
 получить у системы контекст устройства для данного окна;
изменить при необходимости режимы рисования или характеристики конкретных инструментов; 
сформировать с помощью графических функций GDI требуемое изображение;
 вернуть Windows занятый у нее контекст устройства, приведя его предварительно в исходное состояние.
Описание слайда:
Вывод изображения в окно Таким образом, для того чтобы вывести в окно некоторое изображение, необходимо выполнить следующие действия, последовательность которых, в сущности, определяет алгоритм обработки сообщения WM_PAINT: получить у системы контекст устройства для данного окна; изменить при необходимости режимы рисования или характеристики конкретных инструментов; сформировать с помощью графических функций GDI требуемое изображение; вернуть Windows занятый у нее контекст устройства, приведя его предварительно в исходное состояние.

Слайд 23





Все перечисленные действия выполняются в функции OnPaint(). 
Для получения контекста устройства предусмотрена функция BeginPaint(), требующая два параметра. 
Первый параметр представляет собой дескриптор того окна, в котором мы предполагаем рисовать и для которого требуется контекст устройства.
Второй параметр - это адрес структурной переменной типа PAINTSTRUCT, которую функция BeginPaint() заполняет некоторыми данными. 
В случае своего успешного выполнения функция BeginPaint() возвращает дескриптор контекста устройства, который имеет тип HDC (Handle of Device Context).
Описание слайда:
Все перечисленные действия выполняются в функции OnPaint(). Для получения контекста устройства предусмотрена функция BeginPaint(), требующая два параметра. Первый параметр представляет собой дескриптор того окна, в котором мы предполагаем рисовать и для которого требуется контекст устройства. Второй параметр - это адрес структурной переменной типа PAINTSTRUCT, которую функция BeginPaint() заполняет некоторыми данными. В случае своего успешного выполнения функция BeginPaint() возвращает дескриптор контекста устройства, который имеет тип HDC (Handle of Device Context).

Слайд 24





Программа вывода строки
В нашей программе дескриптор контекста устройства поступает в переменную hdc.
В рассматриваемом простом примере изображение на экране представляет собой просто строку текста; для вывода строки используется функция GDI Text0ut(), 
Text0ut(),  в качестве первого параметра требует указания дескриптора контекста устройства. Поскольку никакие элементы контекста устройства в программе не изменяются, вывод строки осуществляется шрифтом, действующим по умолчанию. 
Возврат контекста в Windows осуществляется функцией EndPaint(), использующей те же аргументы, что и функция BeginPaint().
Описание слайда:
Программа вывода строки В нашей программе дескриптор контекста устройства поступает в переменную hdc. В рассматриваемом простом примере изображение на экране представляет собой просто строку текста; для вывода строки используется функция GDI Text0ut(), Text0ut(), в качестве первого параметра требует указания дескриптора контекста устройства. Поскольку никакие элементы контекста устройства в программе не изменяются, вывод строки осуществляется шрифтом, действующим по умолчанию. Возврат контекста в Windows осуществляется функцией EndPaint(), использующей те же аргументы, что и функция BeginPaint().

Слайд 25





Структурная переменная типа PAINTSTRUCT
Функции BeginPaint() и EndPaint() используют структурную переменную (в нашем случае ps) типа PAINTSTRUCT. В то же время в программе она никак не используется. 
Что содержит эта структура?
Описание слайда:
Структурная переменная типа PAINTSTRUCT Функции BeginPaint() и EndPaint() используют структурную переменную (в нашем случае ps) типа PAINTSTRUCT. В то же время в программе она никак не используется. Что содержит эта структура?

Слайд 26





Структура PAINTSTRUCT
Структура PAINTSTRUCT, заполняемая Windows каждый раз, когда приложение перехватывает обработку сообщения WM_PAINT, описана в файле WINUSER.H и содержит следующие элементы:
typedef struct tagPAINTSTRUCT {
HDC hdc;		//Дескриптор выделяемого контекста устройства
BOOL fErase;		//Флаг перерисовки фона окна
RECT rcPaint;		//Область вырезки
BOOL fRestore;		//Зарезервировано
BOOL fIncUpdate;	//Зарезервировано
BYTE rgbReserved[32];	//Зарезервировано для использования Windows
} PAINTSTRUCT;
Описание слайда:
Структура PAINTSTRUCT Структура PAINTSTRUCT, заполняемая Windows каждый раз, когда приложение перехватывает обработку сообщения WM_PAINT, описана в файле WINUSER.H и содержит следующие элементы: typedef struct tagPAINTSTRUCT { HDC hdc; //Дескриптор выделяемого контекста устройства BOOL fErase; //Флаг перерисовки фона окна RECT rcPaint; //Область вырезки BOOL fRestore; //Зарезервировано BOOL fIncUpdate; //Зарезервировано BYTE rgbReserved[32]; //Зарезервировано для использования Windows } PAINTSTRUCT;

Слайд 27





Область вырезки rcPaint
typedef struct tagRECT {
int left;	//x-ко ордината левого верхнего угла прямоугольника 
int top;	//у-координата левого верхнего угла прямоугольника 
int right;	//х-координата правого нижнего угла прямоугольника 
int bottom;	//у-координата правого нижнего угла прямоугольника
} RECT;
Переменные типа RECT чрезвычайно широко используются в программах для Windows, поскольку области экрана, с которыми имеет дело Windows, всегда имеют прямоугольную форму. 
В данном случае переменная ps.rcPaint описывает ту область окна, которая в процессе манипуляций с окном была повреждена и требует перерисовки.
Рассмотрим этот вопрос более подробно.
Описание слайда:
Область вырезки rcPaint typedef struct tagRECT { int left; //x-ко ордината левого верхнего угла прямоугольника int top; //у-координата левого верхнего угла прямоугольника int right; //х-координата правого нижнего угла прямоугольника int bottom; //у-координата правого нижнего угла прямоугольника } RECT; Переменные типа RECT чрезвычайно широко используются в программах для Windows, поскольку области экрана, с которыми имеет дело Windows, всегда имеют прямоугольную форму. В данном случае переменная ps.rcPaint описывает ту область окна, которая в процессе манипуляций с окном была повреждена и требует перерисовки. Рассмотрим этот вопрос более подробно.

Слайд 28






Как уже отмечалось. Windows посылает в приложение (точнее говоря, в окно приложения, в данном случае в главное окно, поскольку других окон в нашем приложении пока нет) сообщение WM_PAINT, во-первых, при первичном создании окна и, во-вторых, всякий раз, когда все окно или его часть, закрытая ранее другим объектом на экране, освобождается и, соответственно, требует перерисовки. Мы также отмечали, что в принципе приложение обязано перерисовать только эту поврежденную часть окна, однако такой алгоритм рисования реализовать очень трудно, и практически всегда окно перерисовывается целиком, хотя на это понапрасну уходит драгоценное процессорное время. В то же время Windows предоставляет нам возможность повысить эффективность программы, передавая при каждом вызове функции BeginPaint() координаты области вырезки. Что представляет собой эта область?Координаты области вырезки определяются относительно начала рабочей области окна. В программе  размеры всего окна составляют 300х100 пикселов, а размеры рабочей области оказываются (за вычетом толщины рамки и ширины линейки заголовка) меньше, а именно 292х73 пиксела. При обработке первого сообщения WM_PAINT функция BeginPaint() передает в программу через переменную ps.rcPaint именно эти координаты:ps. rcPaint=(0, 0, 292,7-3)Чтобы убедиться в этом, проведите такой эксперимент. Запустите приложение 5-1 в отладчике и установите курсор на строкеEndPaint(hwnd,&ps);//Освобождение контекста устройстват. е. после вывода в окно текстовой строки, но еще в пределах функции OnPaint(), где известны значения всех локальных переменных этой функции. Запустите выполнение программы до курсора (клавиша F4). Программа остановится, что будет соответствовать первому поступлению в окно сообщения WM_PAINT. Для вывода на экран содержимого структуры ps следует поставить курсор на имя ps и выбрать команду меню Debug -> Quick Watch. В окне просмотра данных можно будет увидеть значения переменных элемента структуры rcPaint, которые должны составить последовательность {0,0,292,73}.Рис. 5.3. Окно приложения на переднем планеПродолжите выполнение программы до того же предложения, нажав еще раз клавишу F4. Закройте часть окна приложения каким-либо другим окном, например окном приложения даты/времени (окно этого приложения лучше заранее установить так, чтобы оно частично перекрывало окно программы. В результате часть нашего окна скроется (рис. 5.4).Рис. 5.4. Правый угол окна приложения закрыт другим окномТеперь выведите наше приложение на передний план, щелкнув по нему мышью. Так как в этом случае закрытый ранее угол нашего окна должен перерисоваться (ведь Windows никак не может угадать, что у нас там ничего не нарисовано; хотя, если вдуматься, там нарисован фон, который мог бы быть к тому же не белым, а цветньм), в окно нашего приложения посылается сообщение WM_PAINT. Функция BeginPaint(), вызываемая в ходе обработки этого сообщения, передает в программу координаты уже не всего окна, а именно области вырезки:ps.rcPaint=(208,54,292,73)             Как только закрытая ранее часть окна нашего приложения снова появится на экране, в окно поступит сообщение WM_PAINT и в кадре отладчика можно будет увидеть значения границ области вырезки, которые, разумеется, будут зависеть от степени перекрытия окон (рис. 5.5).Легко сообразить, чтоуказанные координаты в точности соответствуют ранее закрытому уголку окна.Повторим этот эксперимент, закрыв окно нашего приложения с левой стороныВ этом случае после снятия закрывающего окна мы получим следующие значения границ области вырезки: ps.rcPaint=(0,6,71,73)Обратите внимание на второе значение этой последовательности - у-координату верхнего края закрывающего окна. Число 6 говорит о том, что границы области вырезки определяются не относительно границ всего окна, а относительно границ его рабочей области. Расстояние между нижним краем строки заголовка и верхним краем окна даты/времени как раз и составляет 6 пикселов.Итак, функция BeginPaint() каждый раз сообщает программе координаты области вырезки. То, что мы не используем эти данные, каждый раз заново перерисовывая все окно, - это уже наше дело. Однако сама Windows, как оказывается, работает более разумно, чем мы. Несмотря на то что мы в ответ на сообщение WM_PAINT полностью восстанавливаем изображение на всем экране (в нашем примере посылаем строку, которая практически простирается от левого края окна до правого), функции GDI реально перерисовывают только ту часть изображения, которая попала в область вырезки. Неповрежденная часть окна физически не перерисовывается, что повышает скорость вывода и уменьшает неприятное мерцание экрана.Таким образом, хотя программа обычно не использует информации об области вырезки, интерфейс GDI руководствуется ею с целью ускорения работы системы.Вывод текстовых строк и простых геометрических фигурРассмотрим программу, которая выводит в главное окно несколько строк текста и ' простые геометрические фигуры - прямоугольники и круги . Результат работы программы изображен на рис. 5.7.Рис. 5.7. Вывод текстовых строк и геометрических фигур//Программа GDI-2. Вывод текста и простых геометрических фигур/*0ператоры препроцессора*/#define STRICT//Строгая проверка типов переменных #include <windows.h>//Два файла с определениями, макросами #include <windowsx.h>//и прототипами функций Windows /*Прототипы используемых в программе функций пользователя*/BOOL OnCreate(HWND, LPCREATESTRUCT);LRESULT CALLBACK WndProc(HWND,UINT, WPARAM, LPARAM); //Оконная функцияvoid OnPaint(HWND);//Прототип функции OnPaint void OnDestroy(HWND);//Прототип функции OnDestroy/*Глобальные переменные, доступные всем функциям*/HPEN hRedPen,hBluePen;//Дескрипторы новых перьев HBRUSH hYellowBrush;//Дескриптор новой кист/*  Главная функция WinMain*/int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int){char szClassName[]="MainWindow";//Произвольное имя класса главного окна char szTitle[]="Программа GDI-2";//Произвольный заголовок окна MSG Msg;//Структура Msg типа MSG для временного хранения сообщений Windows WNDCLASS wc;//Структура we типа WNDCLKSS для задания характеристик окна/*3арегистрируем класс главного окна*/memset (&wc, 0, sizeof (wc) );//Обнуление всех членов структуры wcwc.lpfnWndProc=WndProc;//Определяем оконную процедуру для главного окнаwc.hInstance=hInst;//Дескриптор приложения wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);//Стандартная иконкаwc.hCursor=LoadCursor(NULL,IDC_ARROW);//Стандартный курсор мыши wc.hbrBackground=GetStockBrush(WHITE_BRUSH);//Белая кисть для фона окна wc.lpszClassName=szClassName;//Класс главного окна RegisterClass(&wc);//Вызов функции Windows регистрации класса окна/*Создадим главное окно и сделаем его видимым*/HWND hwnd=CreateWindow(szClassName,szTitle,//Класс и заголовок окнаWS_OVERLAPPEDWINDOW,10,10,300,150,//Стиль окна, его координаты и размеры HWND_DESKTOP,NULL,hInst,NULL);//Родитель, меню, другие параметрыShowWindow(hwnd,SW_SHOWNORMAL);//Вызов функции Windows показа окна/*0рганизуем цикл обработки сообщений*/while(GetMessage(&Msg,NULL,0,0))//Цикл обработки сообщении: ждатьDispatchMessage(&Msg);//сообщения, записать его в msg и передать WndProc return 0;//После выхода из цикла обработки сообщений вернуться в Windows}//Конец функции WinMain /*0конная функция главного окна*/LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){ switch(msg){//Переход по значению msg - коду сообщенияHANDLE_MSG(hwnd,WM_CREATE,OnCreate); //При поступлении сообщения WM_CREATEHANDLE_MSG(hwnd,WM_PAINT,OnPaint);   //При поступлении сообщения WM_PAINT HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);//При завершении пользователем default://В случае всех остальных сообщений Windows обработка ихreturn(DefWindowProc(hwnd,msg,wParam,lParam));//по умолчанию }//Конец оператора switch }//Конец функции WndProc //Функция обработки сообщений HM_CREATEBOOL OnCreate(HWND,LPCREATESTRUCT){hRedPen=CreatePen (PS_SOLID, 5, RGB (128,0, 0) ); //Создадим темно-красное перо hBluePen=CreatePen(PS_SOLID,5,RGB(0,0,255));//Создадим еще синее перо hYellowBrush=CreateSolidBrush(RGB(255,255,0));//Создадим кисть для заливкиreturn TRUE;}//Функция обработки сообщений WM_PAINTvoid OnPaint(HWND hwnd) {PAINTSTRUCT ps;//Структура для функции BeginPaint()TEXTMETRIC tm;//Структура для получения характеристик используемых шрифтовchar szText1[] = "Первая строка текста";char szText2[] = "Вторая строка текста";char szText3[] = "Третья строка текста";HDC hdc   = BeginPaint(hwnd,&ps);//Получим контекст устройства GetTextMetrics(hdc,&tm);//Получим характеристики (метрики) текущего шрифта int nLineHeight = tm.tmHeight+tm.tmExternalLeading;//Вычислим высоту строки TextOut (hdc, 5,0, szText1, strlen (szText1) ) ; //Вывод арки текста цвета1 по умолчаню/*Варьируем местоположение и цвет выводимого на экран текста*/SetTextColor (hdc, RGB (127, 0, 0) );//Установим в контексте темно-красный цвет текста TextOut(hdc,5,nLineHeight,szText2,strlen(szText2));//Вывод на строку ниже SetTextColor (hdc, RGB (0, 127, 0) );//Установим в контексте темно-зеленый цвет текста TextOut(hdc,5,nLineHeight*2,szText3,strlen(szText3));//Вывод езде ниже/*Вывод в окно простых графических фигур*/Rectangle(hdc,5,55,105,105);//Фигуры рисуются пером по умолчанию (черным) Ellipse(hdc,85,60,125,100);//и кистью фона по умолчанию (белой) /*Сменим в контексте устройства перо и кисть*/HPEN hOldPen=SelectPen (hdc, hRedPen) ; //Старое перо сохраним, новое в контекст Rectangle(hdc,155,55,255,105);//Нарисуем еще прямоугольник в другом месте SelectPen(hdc,hBluePen);//Выберем в контекст новое перо      ' HBRUSH hOldBrush=SelectBrush (hdc, hYellowBrush) ; //Выберем в контекст новую кисть Ellipse(hdc,235,60,275,100);//Нарисуем круг новыми пером и кистью/*Восстановим контекст устройства */SelectPen(hdc,hOldPen);//Выберем в контекст старое сохраненное пероSelectBrush(hdc,hOldBrush);//Выберем в контекст старую сохраненную кистьEndPaint(hwnd,&ps);//Освобождение контекста устройства}/*Функция обработки сообщения WM_DESTROY*/void OnDestroy(HWND){DeleteObject(hRedPen);//Уничтожим созданное пероDeleteObject(hBluePen);//Уничтожим созданное пероDeleteObject(hYellowBrush);//Уничтожим созданную кисть.PostQuitMessage(0);//Вызов функции Windows завершения приложения} По своей структуре программа мало отличается от предыдущей. Из текста оконной функции WndProc() видно, что в программе обрабатываются 3 сообщения Windows: WM_CREATE, WM_PAINT и WM_DESTROY. Эти сообщения представляют минимальный набор для любого приложения Windows. Сообщение WM_CREATE посылается в окно после его создания, но еще до вывода на экран. Функция обработки этого сообщения — удобное место для выполнения разнообразных инициализирующих или подготовительных действий: создания графических инструментов, загрузки ресурсов, открытия и, возможно, чтения файлов и пр. В настоящей программе обработка сообщения WM_CREATE используется для создания дополнительных графических: инструментов — перьев и кистей.Функция обработки сообщения WM_DESTROY также используется достаточно стандартным образом — в ней удаляются созданные ранее графические инструменты.Наконец, в функции обработки сообщения WM_PAINT, как это и положено, осуществляется вывод в окно требуемых графических объектов - в данном случае нескольких строк текста и простых геометрических фигур. Особенности вывода текстовых строкВ простейшем случае вывод текста осуществляется с помощью уже использованной нами функции Text0ut(). Функция позволяет задать графические координаты выводимой строки, причем координаты, указываемые в качестве параметров функции, относятся к верхнему левому углу первого знакоместа строки. Поскольку при выводе строк указываются графические координаты, возникает некоторая сложность при выводе на экран нескольких строк, поскольку смещение каждой следующей строки должно быть не меньше высоты предыдущей, а высота строки зависит от вида используемого шрифта. Поэтому в отличие от программ DOS, где можно указывать текстовые координаты строк, в программах для Windows при выводе текста приходится определять характеристики действующего в настоящий момент шрифта.Для определения характеристик (или, как говорят, метрик) текущего шрифта (дескриптор которого находится в контексте устройства) используется структура TEXTMETRIC. В нее входят 20 элементов, определяющих различные характеристикишрифта, в частности флаги насыщенности, курсива, подчеркивания и перечеркивания, условный код гарнитуры, средняя и максимальная ширина символов шрифта и другие. Для определения межстрочного интервала надо воспользоваться двумя элементами структуры TEXTMETRIC: tmHeight - полная высота символов шрифта и tmExtemalLeading - расстояние между строками. Последняя величина часто равна нулю, и для того чтобы строки не налезали друг на друга, межстрочный интервал необходимо устанавливать несколько больше суммы указанных выше значений.Для получения характеристик текущего шрифта в GDI предусмотрена функция GetTextMetrics(), в качестве первого параметра которой передается дескриптор контекста устройства, а в качестве второго - адрес структурной переменной типаTEXTMETRIC.Необходимо иметь в виду, что структура TEXTMETRIC носит чисто информационный характер и используется только для определения, но не для задания характеристик шрифта. Операция придания шрифту требуемых характеристик (гарнитуры, размера и др.) называется созданием шрифта и выполняется с помощью другой структуры- LOGFONT, которая допускает изменение ее элементов. Техника создания шрифтов будет рассмотрена в одном из следующих разделов.Таким образом, при использовании шрифта по умолчанию (т. е. не прибегая к процедуре создания шрифта) можно изменить только те его характеристики, которые непосредственно записываются в контекст устройства. К ним относятсяцвет символов и фона под ними, режим фона знакомест (прозрачный или непрозрачный), интервал между символами и атрибут выравнивания текста относительно заданных в функции Text0ut() координат.    По умолчанию для символов задан черный цвет, для фона - белый. Цвет символов изменяется с помощью функции SetTextColor(), цвет фона под символами — функцией SetBkColor(). Поскольку эти характеристики хранятся в контексте устройства, настройка цвета будет действовать до следующего изменения или до закрытия контекста.Обе функции задания цвета (как и ряд других функций Windows, устанавливающих цвет каких-либо элементов графики) требуют в качестве второго параметра характеристику цвета в виде двухсловного данного типа COLORREF. Что такое тип COLORREF? В интерактивном справочнике можно найти только, что этот тип описывает 32-битовое данное. Чтобы узнать, как оно образуется, надо обратиться к файлу WINGDI.H, где определен макрос RGB(r,g,b), служащий для формирования 32-битового кода цвета по заданным составляющим (красной, зеленой и синей):#deflneRGB(r,g,b)((COLORREF)(((BYTE)(r)|((word)(g)“8))|(((dword)(BYTE)(b))“16)))Даже не вдаваясь в детали этого довольно запутанного определения, можно сообразить, что данное типа COLORREF складывается из трех байтовых составляющих, причем синяя составляющая (параметр b) перед тем, как попасть в результирующее данное, сдвигается на 16 бит влево, занимая после этого байт с номером 2, зеленая составляющая (параметр g) сдвигается на 8 бит влево, занимая байт с номером 1, а красная составляющая (параметр г) остается без изменений, поступая, таким образом, в байт с номером 0. Старший байт (байт 3) результирующего данного не используется (рис. 5.8).Рис. 5.8. Составление кода цвета из трех составляющихЗначения компонентов указываются в макросе RGB виде десятичных или шестнадцатеричных чисел в диапазоне от 0 до 255 каждое. Например, RGB(255,255,255) описывает белый цвет, a RGB(0,0,0) - черный.Поскольку интенсивность каждой составляющей цвета, хранящейся в байте, может принимать любое из 256 значений, такая конструкция позволяет в принципе задавать до 2563 = 16 777 216 цветовых оттенков.Проще всего использовать в макросе RGB значения компонентов, относящихся к 16-цветному режиму. В этом режиме значения компонентов могут составлять только 128 (половинная яркость), 255 (полная яркость компонента) или 0, причем
допускается использовать любые комбинации либо половинной яркости, либо полной, но не их смесь. Результирующий цвет при этом определяется без труда:RGB (128,128,0) - красно-зеленый, т. е. коричневый RGB (255,255,0) - яркий красно-зеленый, т. е. желтый RGB(0,128,128) - сине-зеленый, т. е. бирюзовыйРеально при работе на современном компьютере можно задавать и любые другиесочетания цветовых компонентов, хотя в этом случае не всегда легко предугадать результирующий цвет.В программе дважды используется функция SetTextColor() - перед выводом второй и третьей строк текста. В результате первая строка текста выводится по умолчанию черным цветом, вторая — темно-красным и третья - темно-зеленым. Во всех трех строках символы имеют фон по умолчанию, т. е. белый.Теперь ясно, зачем мы в этой (и предыдущей) программах установили в характеристиках класса окна белую кисть. Если бы кисть была серой, то вывод шрифта по умолчанию привел бы к малоприятному изображению (рис. 5.9).Рис. 5.9. Вывод текста по умолчанию в окно с серым фономТаким образом, в Windows имеются 3 кисти - одна для закрашивания фона окна (ее цвет загружается в структурную переменную типа WNDCLASS при регистрации класса окна), вторая - для фона знакомест под символами шрифта (ее цвет хранится в контексте устройства и по умолчанию он белый) и, как видно из рис. 5.9, еще однакисть, которая определяет цвет закрашивания геометрических фигур. Последняя кисть по умолчанию тоже белая.Каким образом вывести текст на цветной фон? Это можно сделать двумя способами Первый - с помощью функции SetBkColor() изменить цвет фона под символами. Однако для этого надо знать значения всех трех компонентов цвета фона окна. Другой, более удобный способ - задать режим прозрачности знакомест шрифта. Этот режим устанавливается с помощью функции SetBkMode() с параметром TRANSPARENT;SetBkMode(hdc,TRANSPARENT);Режим прозрачности, как и цвет шрифта, записывается в контекст устройства и будет действовать до нового изменения или до закрытия контекста. На рис. 5.10 показан вывод приложения 5-2, в котором перед посылкой в окно второй строки текста был установлен режим прозрачности знакомест.void OnPaint(HWND hwnd) {	PAINTSTRUCT ps;	//Структура для функции BeginPaint()	TEXTMETRIC tm;	//Структура для получения характеристик используемых шрифтов	char szText1[] = "Первая строка текста";	char szText2[] = "Вторая строка текста";	char szText3[] = "Третья строка текста";	HDC hdc		   = BeginPaint(hwnd,&ps);	//Получим контекст устройства 		GetTextMetrics(hdc,&tm);		//Получим характеристики (метрики) текущего шрифта 	int nLineHeight = tm.tmHeight+tm.tmExternalLeading;//Вычислим высоту строки 	TextOut (hdc, 5,0, szText1, strlen (szText1) ) ; //Вывод арки текста цвета1 по умолчаню/*Варьируем местоположение и цвет выводимого на экран текста*/	SetBkMode(hdc,TRANSPARENT);	SetTextColor (hdc, RGB (127, 0, 0) );	//Установим в контексте темно-красный цвет текста 	TextOut(hdc,5,nLineHeight,szText2,strlen(szText2));//Вывод на строку ниже 	SetTextColor (hdc, RGB (0, 127, 0) );	//Установим в контексте темно-зеленый цвет текста 	TextOut(hdc,5,nLineHeight*2,szText3,strlen(szText3));//Вывод езде нижеРис. 5.10. Вывод текста в режиме прозрачности знакоместПроцедуры работы с графическими инструментамиВ настоящем подразделе мы рассмотрим два наиболее употребительных графических инструмента - перо и кисть. Характеристики пера, находящегося в контексте устройства, определяют вид линий, которыми рисуются геометрические фигуры. Характеристики кисти определяют цвет и фактуру внутренних областей замкнутых фигур. В отличие от шрифта, цвет пера или кисти изменить в контексте устройства нельзя, потому что в контексте хранятся не характеристики этих инструментов, а их дескрипторы, следовательно, для изменения характеристик пера или кисти надо создать новые инструменты и поместить в контекст их дескрипторы.При работе с новыми инструментами следует соблюдать определенную стандартную последовательность действий:создание нового инструмента с заданными характеристиками с помощью, например, функций Windows CreatePen() или CreateSolidBrush() (предусмотрены и другие функции, например CreateHatchBrush() для создания штриховой кисти) и получение его дескриптора;загрузка (выбор) в контекст устройства дескриптора созданного инструмента с обязательным сохранением дескриптора аналогичного инструмента по умолчанию; это действие выполняется с помощью функций SelectPen() или SelectBrush();рисование новым инструментом;загрузка (выбор) в контекст устройства инструмента по умолчанию;уничтожение созданных инструментов функцией Delete0bject().Создание нового инструмента можно выполнить в любом месте программы; наиболее естественно это сделать при обработке сообщения WM_CREATE для главного окна или того окна, для которого готовятся новые инструменты. Поскольку в этом случае дескрипторы инструментов определяются в одной функции, используются в другой, а уничтожаются в третьей, их удобно объявить глобальными.Функции выбора и рисования требуют в качестве первого параметра указания дескриптора контекста устройства, поэтому эти функции обычно вызываются в процессе обработки сообщения WM_PAINT после получения контекста устройства функцией BeginPaint(). В контексте устройства хранится только один дескриптор для каждого инструмента; если требуется сначала рисовать, скажем, синим цветом, а затем зеленым, то при переходе к зеленому цвету в контекст устройства следует загрузить дескриптор зеленого инструмента. Повторный выбор в контекст нового дескриптора уже не требует сохранения предыдущего; важно сохранить только дескриптор инструмента по умолчанию. Именно его следует восстановить в контексте устройства перед закрытием контекста функцией EndPaint().Удаление созданных инструментов можно выполнить в функции обработки сообщения WM_DESTROY; можно, конечно, и динамически создавать и удалять инструменты по ходу программы, особенно если инструментов много, а используются они не вперемежку, а последовательно. В частности, и создание, и использование, и удаление инструментов можно выполнить прямо в функции обработки сообщения WM_PAINT(), хотя такой способ не является оптимальным.Остановимся на некоторых деталях создания и использования графических инструментов. Из прототипа функции CreatePen()HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF cirref)видно, что она требует трех параметров. Первый параметр определяет тип линии, которая будет проводиться этим пером. Второй параметр задает толщину пера в пикселах, а третий — его цвет. Функция возвращает дескриптор созданного пера, который затем следует загрузить в контекст устройства. Таблица . Значения первого параметра функции CreatePenOЗначение	Результат	PS_SOLID	Сплошная линия	PS_DASH	Пунктирная линия (только для линий толщиной 1)	PS_DASHDOT	Линия из точек (только для линий толщиной 1)	PS_DASHDOTDOT	Штрихпунктирная линия (только для линий толщиной 1)	PS_NULL	Нуль-перо (невидимо; удобно для заливки фигур без контура)	PS_INSIDEFRAME	Для замкнутых фигур ограничивающие линии проводятся внутри заданных координат фигуры	Функция CreateSolidBrush() позволяет создать только однотонную цветную кисть заданного цвета. Так же как и функция CreatePenQ, она возвращает дескриптор созданной кисти. При необходимости с помощью функции CreateHatchBrushQ можно создать штриховую кисть заданного цвета. В качестве первого параметра этой функции указывается тип штриховки (диагональная, вертикальная и пр.), в качестве второго - цвет.В GDI предусмотрена также функция CreatePattemBrush(), позволяющая создавать, кисти с произвольным рисунком, предварительно созданным в виде растрового изображения.Рассмотрим подробнее возможности использования встроенных графических инструментов. Выше уже отмечалось, что простыми средствами можно изменить только те характеристики графических инструментов, которые непосредственно хранятся в контексте устройства. К ним относятся, например, цвет символов или флаг прозрачности текста. Если же нужно изменить цвет или толщину пера, изобразить цветной фон или вывести крупный текст, то надосоздать необходимый инструмент, выбрать (загрузить) его в контекст устройства илишь затем использовать для построения требуемого изображения.Как уже вскользь упоминалось в гл. 3, для облегчения работы с часто используемыми инструментами в Windows предусмотрен специальный "склад" (stock), на котором хранится очень ограниченный набор встроенных инструментов, которые, соответственно, не надо создавать, а достаточно получить со "склада". Для получения встроенных инструментов используются макросы GetStockPen(), GetStockBrish(), GetStockFont() или обобщенная функция GetStockObject(). Все эти функции возвращают дескриптор встроенного инструмента, который затем так же, как и для создаваемых инструментов, следует выбрать в контекст устройства. Уничтожать встроенные инструменты после завершения работы с ними не требуется. Необходимо только выбрать в контекст сохраненный предварительно инструмент по умолчанию.Стоит отметить, что операторы Windows GetStockPen(), GetStockBrush() и GetStockFont() не являются функциями Windows. Это макросы, описанные в файле WINDOWSX.H. Их назначение - сделать программирование более наглядным и избавить программиста от необходимости при вызове "настоящей" функции GetStockObject() явно преобразовывать типы получаемых дескрипторов. Например, макрос GetStockPen() определяется следующим образом:#define GetStockPen (i)   ( (HPEN) GetStockObject (j))Видно, что при вызове этого макроса фактически вызывается функция Windows GetStockObject(), при этом ее возвращаемое значение преобразуется в тип HPEN (функция GetStockObject() возвращает "обобщенный" дескриптор типа HGDIOBJECT, т. е. "дескриптор объекта GDI").Подобные макросы используются в Windows довольно широко. Так, не функциями Windows, а макросами являются операторы SelectPen(), SelectBrush() и SelectFont(), которые фактически вызывают функцию Windows Select0bject().Для программиста не имеет особого значения, является ли оператор SelectPen()  функций или макросом, и приведенные выше рассуждения носят, можно сказать, схоластический характер. С другой стороны, если вам понадобится справка о формате или особенностях использования оператора SelectPen(), вы не найдете ее в интерактивном справочнике Windows. Там можно получить справку об обобщенной функции SelectObject(), описание же макроса SelectPen() следует искать в файле WINDOWSX.H с помощью какой-либо программы просмотра текста, например встроенной в Norton Commander.Логические шрифтыРазрабатывая изобразительные детали приложения, естественно воспользоваться богатыми возможностями, предоставляемыми системой Windows в части шрифтового оформления документов. Для того чтобы создать красивый и наглядный документ или экранный кадр, приходится использовать шрифты с различным начертанием, оформлением (курсив, жирный, подчеркнутый), размером и пространственной ориентацией. В зависимости от принципа хранения в памяти компьютера формы символов различают растровые (точечные) и масштабируемые шрифты, которые еще называют шрифтами TrueType. Достоинство шрифтов TrueType заключается в том, что они позволяют изменять в широких пределах размер и другие характеристики символов (например, ширину букв) без снижения качества изображения, что и обусловило их широкое применение.Операционная система Windows поставляется с базовым набором растровых и масштабируемых шрифтов с разнообразными начертаниями и характеристиками. Среди них имеются как шрифты с равной шириной всех символов (они традиционно используются, например, в исходных текстах программ), так и более приятные для глаза пропорциональные шрифты, у которых ширина символа зависит от его формы (буква "Ш", например, шире символа "1"). Многие прикладные программы при их установке расширяют базовый набор Windows, добавляя свои шрифты; наконец, можно приобрести и установить в системе наборы шрифтов независимых разработчиков.Работая с какой-либо коммерческой прикладной программой, использующей шрифты, например с текстовым редактором Word или графическим редактором CorelDraw, пользователь может выбирать для оформления документа любые шрифты из установленных в системе, назначая им требуемые характеристики (размер, интервал между символами и т. д.) с помощью средств используемой прикладной программы. Сложнее обстоит дело при разработке собственного приложения Windows. На экран можно вывести только тот шрифт, дескриптор которого загружен в контекст устройства; при необходимости изменить характеристики шрифта надо сначала создать новый шрифт, хотя под этим обманчивым термином понимается не разработка собственного шрифта, а выбор одного из шрифтов, установленных в системе, и придание ему требуемых характеристик.Правда, в системе имеется несколько готовых шрифтов, дескрипторы которых можно получить со склада с помощью макроса SelectFont() или обобщенной функции Select0bject(). Дескриптор одного из них по умолчанию загружается в контекст устройства при его создании, и именно этим шрифтом мы пользовались в предыдущих примерах для вывода в окно текстовых строк. Однако возможности таких шрифтов ограничены, так как они не допускают изменения своих характеристик (кроме цвета).Программа, создающая и использующая несколько логических шрифтовВ приводимой ниже программе 5-3 рассматривается методика создания шрифтов и использование их для формирования наглядного и выразительного документа. Вывод программы приведен на рис. 5.11.Программа GDI3. Создание логических шрифтов /*Операторы препроцессора*/#define STRICT#define XMAX 600//Размер окна по горизонтали #define YMAX 400//Размер окна по вертикали #include <windows.h> #include <windowsx.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);BOOL OnCreate(HWND,LPCREATESTRUCT);void OnPaint(HWND);void OnDestroy(HWND);/*Глобальные переменные*/HFONT hFont1,hFont2,hFont3,hFont4;		//Будут созданы 4 логических шрифтаHBRUSH hBrush;							//Будет создана кисть /*Главная функция WinMain*/int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,int){	char szClassName [ ]="MainWindow";	char szTitle[]="Программа GDI3";	MSG Msg;	WNDCLASS wc;               	memset (&wc, 0, sizeof (wc));	wc.lpfnWndProc=WndProc;	wc.hInstance=hInst;	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);	wc.hCursor=LoadCursor(NULL,IDC_ARROW);	wc.hbrBackground=GetStockBrush(WHITE_BRUSH);	wc.lpszClassName=szClassName;	RegisterClass(&wc);	HWND hwnd=CreateWindow(szClassName,szTitle,WS_OVERLAPPEDWINDOW,			0,0,XMAX,YMAX,HWND_DESKTOP,NULL,hInst,NULL);	ShowWindow(hwnd,SW_SHOWNORMAL);   		while(GetMessage(&Msg,NULL,0,0)) 		DispatchMessage(&Msg);	return 0;} /*0кониая процедура WndProc*/LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){	switch(msg)	{		HANDLE_MSG(hwnd,WM_CREATE,OnCreate);		HANDLE_MSG(hwnd,WM_PAINT,OnPaint);		HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);	default:		return(DefWindowProc(hwnd,msg,wParam,lParam));	}} /*Функция OnCreate обработки сообщения Wf_CREATE*/ BOOL OnCreate(HWND,LPCREATESTRUCT){	char lpszFace1[]="Times New Roman";//Имя Windows для шрифта 	char lpszFace2[]="Arial";//Имя Windows для шрифта 	LOGFONT lf;//Структура LOGFONT для создания логических Шрифтов 	memset(&lf,0,sizeof(lf));//Обнулим структуру 		/*Создадим логический шрифт 1 (для заголовка)*/ 	lf.lfHeight=60;//Размер	strcpy(lf.lfFaceName,lpszFace1);//Скопируем имя шрифта 	hFont1=CreateFontIndirect(&lf);//Создание шрифта/*Создадим логический шрифт 2 (для подзаголовка и цифр лет)*/ 	lf.lfHeight=18;//Размер 	lf.lfItalic=1;//Курсив	strcpy(lf.lfFaceName,lpszFace2);//Скопируем имя шрифта 	hFont2=CreateFontIndirect(&lf);//Создание шрифта 	/*Создадим логический шрифт 3 (для оси у) */ 	lf.lfHeight=18;//Размер 	lf.lfItalic=0;//Отмена курсива 	lf.lfEscapement=900;//yгол наклона 90° 	hFont3=CreateFontIndirect(&lf);//Создание шрифта 		/*Создадим логический шрифт 4 (для шкалы) */ 	lf.lfHeight=16;//Размер 	lf.lfEscapement=0;//Отмена угла наклона 	hFont4=CreateFontIndirect(&lf);//Создание шрифта 		/*Создадим бирюзовую кисть*/hBrush=CreateSolidBrush(RGB(0,127,127));	return TRUE;}/*Функция OnPaint обработки сообщения MS_PAINT*/void OnPaint(HWND hwnd){	RECT r;				//Прямоугольник для. надписей		PAINTSTRUCT ps;		//Для функции BeginPaint()	TEXTMETRIC tm;//Для получения характеристи
 шрифтов	char szMainTitle[]="К
Описание слайда:
Как уже отмечалось. Windows посылает в приложение (точнее говоря, в окно приложения, в данном случае в главное окно, поскольку других окон в нашем приложении пока нет) сообщение WM_PAINT, во-первых, при первичном создании окна и, во-вторых, всякий раз, когда все окно или его часть, закрытая ранее другим объектом на экране, освобождается и, соответственно, требует перерисовки. Мы также отмечали, что в принципе приложение обязано перерисовать только эту поврежденную часть окна, однако такой алгоритм рисования реализовать очень трудно, и практически всегда окно перерисовывается целиком, хотя на это понапрасну уходит драгоценное процессорное время. В то же время Windows предоставляет нам возможность повысить эффективность программы, передавая при каждом вызове функции BeginPaint() координаты области вырезки. Что представляет собой эта область?Координаты области вырезки определяются относительно начала рабочей области окна. В программе размеры всего окна составляют 300х100 пикселов, а размеры рабочей области оказываются (за вычетом толщины рамки и ширины линейки заголовка) меньше, а именно 292х73 пиксела. При обработке первого сообщения WM_PAINT функция BeginPaint() передает в программу через переменную ps.rcPaint именно эти координаты:ps. rcPaint=(0, 0, 292,7-3)Чтобы убедиться в этом, проведите такой эксперимент. Запустите приложение 5-1 в отладчике и установите курсор на строкеEndPaint(hwnd,&ps);//Освобождение контекста устройстват. е. после вывода в окно текстовой строки, но еще в пределах функции OnPaint(), где известны значения всех локальных переменных этой функции. Запустите выполнение программы до курсора (клавиша F4). Программа остановится, что будет соответствовать первому поступлению в окно сообщения WM_PAINT. Для вывода на экран содержимого структуры ps следует поставить курсор на имя ps и выбрать команду меню Debug -> Quick Watch. В окне просмотра данных можно будет увидеть значения переменных элемента структуры rcPaint, которые должны составить последовательность {0,0,292,73}.Рис. 5.3. Окно приложения на переднем планеПродолжите выполнение программы до того же предложения, нажав еще раз клавишу F4. Закройте часть окна приложения каким-либо другим окном, например окном приложения даты/времени (окно этого приложения лучше заранее установить так, чтобы оно частично перекрывало окно программы. В результате часть нашего окна скроется (рис. 5.4).Рис. 5.4. Правый угол окна приложения закрыт другим окномТеперь выведите наше приложение на передний план, щелкнув по нему мышью. Так как в этом случае закрытый ранее угол нашего окна должен перерисоваться (ведь Windows никак не может угадать, что у нас там ничего не нарисовано; хотя, если вдуматься, там нарисован фон, который мог бы быть к тому же не белым, а цветньм), в окно нашего приложения посылается сообщение WM_PAINT. Функция BeginPaint(), вызываемая в ходе обработки этого сообщения, передает в программу координаты уже не всего окна, а именно области вырезки:ps.rcPaint=(208,54,292,73) Как только закрытая ранее часть окна нашего приложения снова появится на экране, в окно поступит сообщение WM_PAINT и в кадре отладчика можно будет увидеть значения границ области вырезки, которые, разумеется, будут зависеть от степени перекрытия окон (рис. 5.5).Легко сообразить, чтоуказанные координаты в точности соответствуют ранее закрытому уголку окна.Повторим этот эксперимент, закрыв окно нашего приложения с левой стороныВ этом случае после снятия закрывающего окна мы получим следующие значения границ области вырезки: ps.rcPaint=(0,6,71,73)Обратите внимание на второе значение этой последовательности - у-координату верхнего края закрывающего окна. Число 6 говорит о том, что границы области вырезки определяются не относительно границ всего окна, а относительно границ его рабочей области. Расстояние между нижним краем строки заголовка и верхним краем окна даты/времени как раз и составляет 6 пикселов.Итак, функция BeginPaint() каждый раз сообщает программе координаты области вырезки. То, что мы не используем эти данные, каждый раз заново перерисовывая все окно, - это уже наше дело. Однако сама Windows, как оказывается, работает более разумно, чем мы. Несмотря на то что мы в ответ на сообщение WM_PAINT полностью восстанавливаем изображение на всем экране (в нашем примере посылаем строку, которая практически простирается от левого края окна до правого), функции GDI реально перерисовывают только ту часть изображения, которая попала в область вырезки. Неповрежденная часть окна физически не перерисовывается, что повышает скорость вывода и уменьшает неприятное мерцание экрана.Таким образом, хотя программа обычно не использует информации об области вырезки, интерфейс GDI руководствуется ею с целью ускорения работы системы.Вывод текстовых строк и простых геометрических фигурРассмотрим программу, которая выводит в главное окно несколько строк текста и ' простые геометрические фигуры - прямоугольники и круги . Результат работы программы изображен на рис. 5.7.Рис. 5.7. Вывод текстовых строк и геометрических фигур//Программа GDI-2. Вывод текста и простых геометрических фигур/*0ператоры препроцессора*/#define STRICT//Строгая проверка типов переменных #include <windows.h>//Два файла с определениями, макросами #include <windowsx.h>//и прототипами функций Windows /*Прототипы используемых в программе функций пользователя*/BOOL OnCreate(HWND, LPCREATESTRUCT);LRESULT CALLBACK WndProc(HWND,UINT, WPARAM, LPARAM); //Оконная функцияvoid OnPaint(HWND);//Прототип функции OnPaint void OnDestroy(HWND);//Прототип функции OnDestroy/*Глобальные переменные, доступные всем функциям*/HPEN hRedPen,hBluePen;//Дескрипторы новых перьев HBRUSH hYellowBrush;//Дескриптор новой кист/* Главная функция WinMain*/int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int){char szClassName[]="MainWindow";//Произвольное имя класса главного окна char szTitle[]="Программа GDI-2";//Произвольный заголовок окна MSG Msg;//Структура Msg типа MSG для временного хранения сообщений Windows WNDCLASS wc;//Структура we типа WNDCLKSS для задания характеристик окна/*3арегистрируем класс главного окна*/memset (&wc, 0, sizeof (wc) );//Обнуление всех членов структуры wcwc.lpfnWndProc=WndProc;//Определяем оконную процедуру для главного окнаwc.hInstance=hInst;//Дескриптор приложения wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);//Стандартная иконкаwc.hCursor=LoadCursor(NULL,IDC_ARROW);//Стандартный курсор мыши wc.hbrBackground=GetStockBrush(WHITE_BRUSH);//Белая кисть для фона окна wc.lpszClassName=szClassName;//Класс главного окна RegisterClass(&wc);//Вызов функции Windows регистрации класса окна/*Создадим главное окно и сделаем его видимым*/HWND hwnd=CreateWindow(szClassName,szTitle,//Класс и заголовок окнаWS_OVERLAPPEDWINDOW,10,10,300,150,//Стиль окна, его координаты и размеры HWND_DESKTOP,NULL,hInst,NULL);//Родитель, меню, другие параметрыShowWindow(hwnd,SW_SHOWNORMAL);//Вызов функции Windows показа окна/*0рганизуем цикл обработки сообщений*/while(GetMessage(&Msg,NULL,0,0))//Цикл обработки сообщении: ждатьDispatchMessage(&Msg);//сообщения, записать его в msg и передать WndProc return 0;//После выхода из цикла обработки сообщений вернуться в Windows}//Конец функции WinMain /*0конная функция главного окна*/LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){ switch(msg){//Переход по значению msg - коду сообщенияHANDLE_MSG(hwnd,WM_CREATE,OnCreate); //При поступлении сообщения WM_CREATEHANDLE_MSG(hwnd,WM_PAINT,OnPaint); //При поступлении сообщения WM_PAINT HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);//При завершении пользователем default://В случае всех остальных сообщений Windows обработка ихreturn(DefWindowProc(hwnd,msg,wParam,lParam));//по умолчанию }//Конец оператора switch }//Конец функции WndProc //Функция обработки сообщений HM_CREATEBOOL OnCreate(HWND,LPCREATESTRUCT){hRedPen=CreatePen (PS_SOLID, 5, RGB (128,0, 0) ); //Создадим темно-красное перо hBluePen=CreatePen(PS_SOLID,5,RGB(0,0,255));//Создадим еще синее перо hYellowBrush=CreateSolidBrush(RGB(255,255,0));//Создадим кисть для заливкиreturn TRUE;}//Функция обработки сообщений WM_PAINTvoid OnPaint(HWND hwnd) {PAINTSTRUCT ps;//Структура для функции BeginPaint()TEXTMETRIC tm;//Структура для получения характеристик используемых шрифтовchar szText1[] = "Первая строка текста";char szText2[] = "Вторая строка текста";char szText3[] = "Третья строка текста";HDC hdc = BeginPaint(hwnd,&ps);//Получим контекст устройства GetTextMetrics(hdc,&tm);//Получим характеристики (метрики) текущего шрифта int nLineHeight = tm.tmHeight+tm.tmExternalLeading;//Вычислим высоту строки TextOut (hdc, 5,0, szText1, strlen (szText1) ) ; //Вывод арки текста цвета1 по умолчаню/*Варьируем местоположение и цвет выводимого на экран текста*/SetTextColor (hdc, RGB (127, 0, 0) );//Установим в контексте темно-красный цвет текста TextOut(hdc,5,nLineHeight,szText2,strlen(szText2));//Вывод на строку ниже SetTextColor (hdc, RGB (0, 127, 0) );//Установим в контексте темно-зеленый цвет текста TextOut(hdc,5,nLineHeight*2,szText3,strlen(szText3));//Вывод езде ниже/*Вывод в окно простых графических фигур*/Rectangle(hdc,5,55,105,105);//Фигуры рисуются пером по умолчанию (черным) Ellipse(hdc,85,60,125,100);//и кистью фона по умолчанию (белой) /*Сменим в контексте устройства перо и кисть*/HPEN hOldPen=SelectPen (hdc, hRedPen) ; //Старое перо сохраним, новое в контекст Rectangle(hdc,155,55,255,105);//Нарисуем еще прямоугольник в другом месте SelectPen(hdc,hBluePen);//Выберем в контекст новое перо ' HBRUSH hOldBrush=SelectBrush (hdc, hYellowBrush) ; //Выберем в контекст новую кисть Ellipse(hdc,235,60,275,100);//Нарисуем круг новыми пером и кистью/*Восстановим контекст устройства */SelectPen(hdc,hOldPen);//Выберем в контекст старое сохраненное пероSelectBrush(hdc,hOldBrush);//Выберем в контекст старую сохраненную кистьEndPaint(hwnd,&ps);//Освобождение контекста устройства}/*Функция обработки сообщения WM_DESTROY*/void OnDestroy(HWND){DeleteObject(hRedPen);//Уничтожим созданное пероDeleteObject(hBluePen);//Уничтожим созданное пероDeleteObject(hYellowBrush);//Уничтожим созданную кисть.PostQuitMessage(0);//Вызов функции Windows завершения приложения} По своей структуре программа мало отличается от предыдущей. Из текста оконной функции WndProc() видно, что в программе обрабатываются 3 сообщения Windows: WM_CREATE, WM_PAINT и WM_DESTROY. Эти сообщения представляют минимальный набор для любого приложения Windows. Сообщение WM_CREATE посылается в окно после его создания, но еще до вывода на экран. Функция обработки этого сообщения — удобное место для выполнения разнообразных инициализирующих или подготовительных действий: создания графических инструментов, загрузки ресурсов, открытия и, возможно, чтения файлов и пр. В настоящей программе обработка сообщения WM_CREATE используется для создания дополнительных графических: инструментов — перьев и кистей.Функция обработки сообщения WM_DESTROY также используется достаточно стандартным образом — в ней удаляются созданные ранее графические инструменты.Наконец, в функции обработки сообщения WM_PAINT, как это и положено, осуществляется вывод в окно требуемых графических объектов - в данном случае нескольких строк текста и простых геометрических фигур. Особенности вывода текстовых строкВ простейшем случае вывод текста осуществляется с помощью уже использованной нами функции Text0ut(). Функция позволяет задать графические координаты выводимой строки, причем координаты, указываемые в качестве параметров функции, относятся к верхнему левому углу первого знакоместа строки. Поскольку при выводе строк указываются графические координаты, возникает некоторая сложность при выводе на экран нескольких строк, поскольку смещение каждой следующей строки должно быть не меньше высоты предыдущей, а высота строки зависит от вида используемого шрифта. Поэтому в отличие от программ DOS, где можно указывать текстовые координаты строк, в программах для Windows при выводе текста приходится определять характеристики действующего в настоящий момент шрифта.Для определения характеристик (или, как говорят, метрик) текущего шрифта (дескриптор которого находится в контексте устройства) используется структура TEXTMETRIC. В нее входят 20 элементов, определяющих различные характеристикишрифта, в частности флаги насыщенности, курсива, подчеркивания и перечеркивания, условный код гарнитуры, средняя и максимальная ширина символов шрифта и другие. Для определения межстрочного интервала надо воспользоваться двумя элементами структуры TEXTMETRIC: tmHeight - полная высота символов шрифта и tmExtemalLeading - расстояние между строками. Последняя величина часто равна нулю, и для того чтобы строки не налезали друг на друга, межстрочный интервал необходимо устанавливать несколько больше суммы указанных выше значений.Для получения характеристик текущего шрифта в GDI предусмотрена функция GetTextMetrics(), в качестве первого параметра которой передается дескриптор контекста устройства, а в качестве второго - адрес структурной переменной типаTEXTMETRIC.Необходимо иметь в виду, что структура TEXTMETRIC носит чисто информационный характер и используется только для определения, но не для задания характеристик шрифта. Операция придания шрифту требуемых характеристик (гарнитуры, размера и др.) называется созданием шрифта и выполняется с помощью другой структуры- LOGFONT, которая допускает изменение ее элементов. Техника создания шрифтов будет рассмотрена в одном из следующих разделов.Таким образом, при использовании шрифта по умолчанию (т. е. не прибегая к процедуре создания шрифта) можно изменить только те его характеристики, которые непосредственно записываются в контекст устройства. К ним относятсяцвет символов и фона под ними, режим фона знакомест (прозрачный или непрозрачный), интервал между символами и атрибут выравнивания текста относительно заданных в функции Text0ut() координат. По умолчанию для символов задан черный цвет, для фона - белый. Цвет символов изменяется с помощью функции SetTextColor(), цвет фона под символами — функцией SetBkColor(). Поскольку эти характеристики хранятся в контексте устройства, настройка цвета будет действовать до следующего изменения или до закрытия контекста.Обе функции задания цвета (как и ряд других функций Windows, устанавливающих цвет каких-либо элементов графики) требуют в качестве второго параметра характеристику цвета в виде двухсловного данного типа COLORREF. Что такое тип COLORREF? В интерактивном справочнике можно найти только, что этот тип описывает 32-битовое данное. Чтобы узнать, как оно образуется, надо обратиться к файлу WINGDI.H, где определен макрос RGB(r,g,b), служащий для формирования 32-битового кода цвета по заданным составляющим (красной, зеленой и синей):#deflneRGB(r,g,b)((COLORREF)(((BYTE)(r)|((word)(g)“8))|(((dword)(BYTE)(b))“16)))Даже не вдаваясь в детали этого довольно запутанного определения, можно сообразить, что данное типа COLORREF складывается из трех байтовых составляющих, причем синяя составляющая (параметр b) перед тем, как попасть в результирующее данное, сдвигается на 16 бит влево, занимая после этого байт с номером 2, зеленая составляющая (параметр g) сдвигается на 8 бит влево, занимая байт с номером 1, а красная составляющая (параметр г) остается без изменений, поступая, таким образом, в байт с номером 0. Старший байт (байт 3) результирующего данного не используется (рис. 5.8).Рис. 5.8. Составление кода цвета из трех составляющихЗначения компонентов указываются в макросе RGB виде десятичных или шестнадцатеричных чисел в диапазоне от 0 до 255 каждое. Например, RGB(255,255,255) описывает белый цвет, a RGB(0,0,0) - черный.Поскольку интенсивность каждой составляющей цвета, хранящейся в байте, может принимать любое из 256 значений, такая конструкция позволяет в принципе задавать до 2563 = 16 777 216 цветовых оттенков.Проще всего использовать в макросе RGB значения компонентов, относящихся к 16-цветному режиму. В этом режиме значения компонентов могут составлять только 128 (половинная яркость), 255 (полная яркость компонента) или 0, причем допускается использовать любые комбинации либо половинной яркости, либо полной, но не их смесь. Результирующий цвет при этом определяется без труда: RGB (128,128,0) - красно-зеленый, т. е. коричневый RGB (255,255,0) - яркий красно-зеленый, т. е. желтый RGB(0,128,128) - сине-зеленый, т. е. бирюзовый Реально при работе на современном компьютере можно задавать и любые другие сочетания цветовых компонентов, хотя в этом случае не всегда легко предугадать результирующий цвет. В программе дважды используется функция SetTextColor() - перед выводом второй и третьей строк текста. В результате первая строка текста выводится по умолчанию черным цветом, вторая — темно-красным и третья - темно-зеленым. Во всех трех строках символы имеют фон по умолчанию, т. е. белый. Теперь ясно, зачем мы в этой (и предыдущей) программах установили в характеристиках класса окна белую кисть. Если бы кисть была серой, то вывод шрифта по умолчанию привел бы к малоприятному изображению (рис. 5.9). Рис. 5.9. Вывод текста по умолчанию в окно с серым фоном Таким образом, в Windows имеются 3 кисти - одна для закрашивания фона окна (ее цвет загружается в структурную переменную типа WNDCLASS при регистрации класса окна), вторая - для фона знакомест под символами шрифта (ее цвет хранится в контексте устройства и по умолчанию он белый) и, как видно из рис. 5.9, еще однакисть, которая определяет цвет закрашивания геометрических фигур. Последняя кисть по умолчанию тоже белая. Каким образом вывести текст на цветной фон? Это можно сделать двумя способами Первый - с помощью функции SetBkColor() изменить цвет фона под символами. Однако для этого надо знать значения всех трех компонентов цвета фона окна. Другой, более удобный способ - задать режим прозрачности знакомест шрифта. Этот режим устанавливается с помощью функции SetBkMode() с параметром TRANSPARENT; SetBkMode(hdc,TRANSPARENT); Режим прозрачности, как и цвет шрифта, записывается в контекст устройства и будет действовать до нового изменения или до закрытия контекста. На рис. 5.10 показан вывод приложения 5-2, в котором перед посылкой в окно второй строки текста был установлен режим прозрачности знакомест. void OnPaint(HWND hwnd) { PAINTSTRUCT ps; //Структура для функции BeginPaint() TEXTMETRIC tm; //Структура для получения характеристик используемых шрифтов char szText1[] = "Первая строка текста"; char szText2[] = "Вторая строка текста"; char szText3[] = "Третья строка текста"; HDC hdc = BeginPaint(hwnd,&ps); //Получим контекст устройства GetTextMetrics(hdc,&tm); //Получим характеристики (метрики) текущего шрифта int nLineHeight = tm.tmHeight+tm.tmExternalLeading;//Вычислим высоту строки TextOut (hdc, 5,0, szText1, strlen (szText1) ) ; //Вывод арки текста цвета1 по умолчаню /*Варьируем местоположение и цвет выводимого на экран текста*/ SetBkMode(hdc,TRANSPARENT); SetTextColor (hdc, RGB (127, 0, 0) ); //Установим в контексте темно-красный цвет текста TextOut(hdc,5,nLineHeight,szText2,strlen(szText2));//Вывод на строку ниже SetTextColor (hdc, RGB (0, 127, 0) ); //Установим в контексте темно-зеленый цвет текста TextOut(hdc,5,nLineHeight*2,szText3,strlen(szText3));//Вывод езде ниже Рис. 5.10. Вывод текста в режиме прозрачности знакомест Процедуры работы с графическими инструментами В настоящем подразделе мы рассмотрим два наиболее употребительных графических инструмента - перо и кисть. Характеристики пера, находящегося в контексте устройства, определяют вид линий, которыми рисуются геометрические фигуры. Характеристики кисти определяют цвет и фактуру внутренних областей замкнутых фигур. В отличие от шрифта, цвет пера или кисти изменить в контексте устройства нельзя, потому что в контексте хранятся не характеристики этих инструментов, а их дескрипторы, следовательно, для изменения характеристик пера или кисти надо создать новые инструменты и поместить в контекст их дескрипторы. При работе с новыми инструментами следует соблюдать определенную стандартную последовательность действий: создание нового инструмента с заданными характеристиками с помощью, например, функций Windows CreatePen() или CreateSolidBrush() (предусмотрены и другие функции, например CreateHatchBrush() для создания штриховой кисти) и получение его дескриптора; загрузка (выбор) в контекст устройства дескриптора созданного инструмента с обязательным сохранением дескриптора аналогичного инструмента по умолчанию; это действие выполняется с помощью функций SelectPen() или SelectBrush(); рисование новым инструментом; загрузка (выбор) в контекст устройства инструмента по умолчанию; уничтожение созданных инструментов функцией Delete0bject(). Создание нового инструмента можно выполнить в любом месте программы; наиболее естественно это сделать при обработке сообщения WM_CREATE для главного окна или того окна, для которого готовятся новые инструменты. Поскольку в этом случае дескрипторы инструментов определяются в одной функции, используются в другой, а уничтожаются в третьей, их удобно объявить глобальными. Функции выбора и рисования требуют в качестве первого параметра указания дескриптора контекста устройства, поэтому эти функции обычно вызываются в процессе обработки сообщения WM_PAINT после получения контекста устройства функцией BeginPaint(). В контексте устройства хранится только один дескриптор для каждого инструмента; если требуется сначала рисовать, скажем, синим цветом, а затем зеленым, то при переходе к зеленому цвету в контекст устройства следует загрузить дескриптор зеленого инструмента. Повторный выбор в контекст нового дескриптора уже не требует сохранения предыдущего; важно сохранить только дескриптор инструмента по умолчанию. Именно его следует восстановить в контексте устройства перед закрытием контекста функцией EndPaint(). Удаление созданных инструментов можно выполнить в функции обработки сообщения WM_DESTROY; можно, конечно, и динамически создавать и удалять инструменты по ходу программы, особенно если инструментов много, а используются они не вперемежку, а последовательно. В частности, и создание, и использование, и удаление инструментов можно выполнить прямо в функции обработки сообщения WM_PAINT(), хотя такой способ не является оптимальным. Остановимся на некоторых деталях создания и использования графических инструментов. Из прототипа функции CreatePen() HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF cirref) видно, что она требует трех параметров. Первый параметр определяет тип линии, которая будет проводиться этим пером. Второй параметр задает толщину пера в пикселах, а третий — его цвет. Функция возвращает дескриптор созданного пера, который затем следует загрузить в контекст устройства. Таблица . Значения первого параметра функции CreatePenO Значение Результат PS_SOLID Сплошная линия PS_DASH Пунктирная линия (только для линий толщиной 1) PS_DASHDOT Линия из точек (только для линий толщиной 1) PS_DASHDOTDOT Штрихпунктирная линия (только для линий толщиной 1) PS_NULL Нуль-перо (невидимо; удобно для заливки фигур без контура) PS_INSIDEFRAME Для замкнутых фигур ограничивающие линии проводятся внутри заданных координат фигуры Функция CreateSolidBrush() позволяет создать только однотонную цветную кисть заданного цвета. Так же как и функция CreatePenQ, она возвращает дескриптор созданной кисти. При необходимости с помощью функции CreateHatchBrushQ можно создать штриховую кисть заданного цвета. В качестве первого параметра этой функции указывается тип штриховки (диагональная, вертикальная и пр.), в качестве второго - цвет. В GDI предусмотрена также функция CreatePattemBrush(), позволяющая создавать, кисти с произвольным рисунком, предварительно созданным в виде растрового изображения. Рассмотрим подробнее возможности использования встроенных графических инструментов. Выше уже отмечалось, что простыми средствами можно изменить только те характеристики графических инструментов, которые непосредственно хранятся в контексте устройства. К ним относятся, например, цвет символов или флаг прозрачности текста. Если же нужно изменить цвет или толщину пера, изобразить цветной фон или вывести крупный текст, то надо создать необходимый инструмент, выбрать (загрузить) его в контекст устройства и лишь затем использовать для построения требуемого изображения. Как уже вскользь упоминалось в гл. 3, для облегчения работы с часто используемыми инструментами в Windows предусмотрен специальный "склад" (stock), на котором хранится очень ограниченный набор встроенных инструментов, которые, соответственно, не надо создавать, а достаточно получить со "склада". Для получения встроенных инструментов используются макросы GetStockPen(), GetStockBrish(), GetStockFont() или обобщенная функция GetStockObject(). Все эти функции возвращают дескриптор встроенного инструмента, который затем так же, как и для создаваемых инструментов, следует выбрать в контекст устройства. Уничтожать встроенные инструменты после завершения работы с ними не требуется. Необходимо только выбрать в контекст сохраненный предварительно инструмент по умолчанию. Стоит отметить, что операторы Windows GetStockPen(), GetStockBrush() и GetStockFont() не являются функциями Windows. Это макросы, описанные в файле WINDOWSX.H. Их назначение - сделать программирование более наглядным и избавить программиста от необходимости при вызове "настоящей" функции GetStockObject() явно преобразовывать типы получаемых дескрипторов. Например, макрос GetStockPen() определяется следующим образом: #define GetStockPen (i) ( (HPEN) GetStockObject (j)) Видно, что при вызове этого макроса фактически вызывается функция Windows GetStockObject(), при этом ее возвращаемое значение преобразуется в тип HPEN (функция GetStockObject() возвращает "обобщенный" дескриптор типа HGDIOBJECT, т. е. "дескриптор объекта GDI"). Подобные макросы используются в Windows довольно широко. Так, не функциями Windows, а макросами являются операторы SelectPen(), SelectBrush() и SelectFont(), которые фактически вызывают функцию Windows Select0bject(). Для программиста не имеет особого значения, является ли оператор SelectPen() функций или макросом, и приведенные выше рассуждения носят, можно сказать, схоластический характер. С другой стороны, если вам понадобится справка о формате или особенностях использования оператора SelectPen(), вы не найдете ее в интерактивном справочнике Windows. Там можно получить справку об обобщенной функции SelectObject(), описание же макроса SelectPen() следует искать в файле WINDOWSX.H с помощью какой-либо программы просмотра текста, например встроенной в Norton Commander. Логические шрифты Разрабатывая изобразительные детали приложения, естественно воспользоваться богатыми возможностями, предоставляемыми системой Windows в части шрифтового оформления документов. Для того чтобы создать красивый и наглядный документ или экранный кадр, приходится использовать шрифты с различным начертанием, оформлением (курсив, жирный, подчеркнутый), размером и пространственной ориентацией. В зависимости от принципа хранения в памяти компьютера формы символов различают растровые (точечные) и масштабируемые шрифты, которые еще называют шрифтами TrueType. Достоинство шрифтов TrueType заключается в том, что они позволяют изменять в широких пределах размер и другие характеристики символов (например, ширину букв) без снижения качества изображения, что и обусловило их широкое применение. Операционная система Windows поставляется с базовым набором растровых и масштабируемых шрифтов с разнообразными начертаниями и характеристиками. Среди них имеются как шрифты с равной шириной всех символов (они традиционно используются, например, в исходных текстах программ), так и более приятные для глаза пропорциональные шрифты, у которых ширина символа зависит от его формы (буква "Ш", например, шире символа "1"). Многие прикладные программы при их установке расширяют базовый набор Windows, добавляя свои шрифты; наконец, можно приобрести и установить в системе наборы шрифтов независимых разработчиков. Работая с какой-либо коммерческой прикладной программой, использующей шрифты, например с текстовым редактором Word или графическим редактором CorelDraw, пользователь может выбирать для оформления документа любые шрифты из установленных в системе, назначая им требуемые характеристики (размер, интервал между символами и т. д.) с помощью средств используемой прикладной программы. Сложнее обстоит дело при разработке собственного приложения Windows. На экран можно вывести только тот шрифт, дескриптор которого загружен в контекст устройства; при необходимости изменить характеристики шрифта надо сначала создать новый шрифт, хотя под этим обманчивым термином понимается не разработка собственного шрифта, а выбор одного из шрифтов, установленных в системе, и придание ему требуемых характеристик. Правда, в системе имеется несколько готовых шрифтов, дескрипторы которых можно получить со склада с помощью макроса SelectFont() или обобщенной функции Select0bject(). Дескриптор одного из них по умолчанию загружается в контекст устройства при его создании, и именно этим шрифтом мы пользовались в предыдущих примерах для вывода в окно текстовых строк. Однако возможности таких шрифтов ограничены, так как они не допускают изменения своих характеристик (кроме цвета). Программа, создающая и использующая несколько логических шрифтов В приводимой ниже программе 5-3 рассматривается методика создания шрифтов и использование их для формирования наглядного и выразительного документа. Вывод программы приведен на рис. 5.11. Программа GDI3. Создание логических шрифтов /*Операторы препроцессора*/ #define STRICT #define XMAX 600//Размер окна по горизонтали #define YMAX 400//Размер окна по вертикали #include <windows.h> #include <windowsx.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); BOOL OnCreate(HWND,LPCREATESTRUCT); void OnPaint(HWND); void OnDestroy(HWND); /*Глобальные переменные*/ HFONT hFont1,hFont2,hFont3,hFont4; //Будут созданы 4 логических шрифта HBRUSH hBrush; //Будет создана кисть /*Главная функция WinMain*/ int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,int) { char szClassName [ ]="MainWindow"; char szTitle[]="Программа GDI3"; MSG Msg; WNDCLASS wc; memset (&wc, 0, sizeof (wc)); wc.lpfnWndProc=WndProc; wc.hInstance=hInst; wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW); wc.hbrBackground=GetStockBrush(WHITE_BRUSH); wc.lpszClassName=szClassName; RegisterClass(&wc); HWND hwnd=CreateWindow(szClassName,szTitle,WS_OVERLAPPEDWINDOW, 0,0,XMAX,YMAX,HWND_DESKTOP,NULL,hInst,NULL); ShowWindow(hwnd,SW_SHOWNORMAL); while(GetMessage(&Msg,NULL,0,0)) DispatchMessage(&Msg); return 0; } /*0кониая процедура WndProc*/ LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch(msg) { HANDLE_MSG(hwnd,WM_CREATE,OnCreate); HANDLE_MSG(hwnd,WM_PAINT,OnPaint); HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy); default: return(DefWindowProc(hwnd,msg,wParam,lParam)); } } /*Функция OnCreate обработки сообщения Wf_CREATE*/ BOOL OnCreate(HWND,LPCREATESTRUCT) { char lpszFace1[]="Times New Roman";//Имя Windows для шрифта char lpszFace2[]="Arial";//Имя Windows для шрифта LOGFONT lf;//Структура LOGFONT для создания логических Шрифтов memset(&lf,0,sizeof(lf));//Обнулим структуру /*Создадим логический шрифт 1 (для заголовка)*/ lf.lfHeight=60;//Размер strcpy(lf.lfFaceName,lpszFace1);//Скопируем имя шрифта hFont1=CreateFontIndirect(&lf);//Создание шрифта /*Создадим логический шрифт 2 (для подзаголовка и цифр лет)*/ lf.lfHeight=18;//Размер lf.lfItalic=1;//Курсив strcpy(lf.lfFaceName,lpszFace2);//Скопируем имя шрифта hFont2=CreateFontIndirect(&lf);//Создание шрифта /*Создадим логический шрифт 3 (для оси у) */ lf.lfHeight=18;//Размер lf.lfItalic=0;//Отмена курсива lf.lfEscapement=900;//yгол наклона 90° hFont3=CreateFontIndirect(&lf);//Создание шрифта /*Создадим логический шрифт 4 (для шкалы) */ lf.lfHeight=16;//Размер lf.lfEscapement=0;//Отмена угла наклона hFont4=CreateFontIndirect(&lf);//Создание шрифта /*Создадим бирюзовую кисть*/ hBrush=CreateSolidBrush(RGB(0,127,127)); return TRUE; } /*Функция OnPaint обработки сообщения MS_PAINT*/ void OnPaint(HWND hwnd) { RECT r; //Прямоугольник для. надписей PAINTSTRUCT ps; //Для функции BeginPaint() TEXTMETRIC tm;//Для получения характеристи шрифтов char szMainTitle[]="К



Похожие презентации
Mypresentation.ru
Загрузить презентацию