Компьютерная графика. Лабораторная работа 1_2п. Лабораторная работа основы создания графических приложений в системе windows
Скачать 0.96 Mb.
|
CALLBACK задаёт способ вызова функции, используемый Windows для осуществления вызовов пользовательских процедур. Когда сообщение отправлено функции WinProc , его следует обработать. Стандартная политика обработки – создать оператор switch и заниматься различными событиями в различных вариантах ( case ). Вот так выглядит основа структуры: switch (uMsg) { } Теперь можно сравнивать uMsg с различными видами сообщений, чтобы определить, какое именно получено. Например, сообщение с идентификатором WM_PAINT , которое сообщает приложению о том, что клиентская область окна или её часть нуждается в перерисовке, может быть определено следующим образом: case WM_PAINT: hdc = BeginPaint(hWnd,&ps); GetClientRect(hWnd,&rect); DrawText(hdc,"Hello, world!",-1,&rect,DT_CENTER); EndPaint(hWnd,&ps); break; Поскольку различных видов сообщений невероятно много, обработку большей части из них можно делегировать функции DefWindowProc , оставив при этом обработку интересующих сообщений функции WinProc . Вызов функции DefWindowProc выглядит следующим образом: DefWindowProc(hWnd, uMsg, wParam, lParam); И хотя большая часть сообщений, как правило, обрабатывается системой, некоторые из них необходимо обрабатывать самостоятельно. Поэтому вызов функции DefWindowProc помещается в вариант по умолчанию оператора switch следующим образом: switch (uMsg) { default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } Возвращаемое значение DefWindowProc интерпретируется так же, как возвращаемое значение WinProc , так что это значение можно возвращать без предварительной обработки. Окончательная версия: switch (uMsg) { case WM_SOMETHING: //выполняем действия default: return DefWindowProc(hWnd, messg, wParam, lParam); } return 0; Кроме рассмотренных сообщений в оконной процедуре, как правило, обрабатываются такие сообщения, как WM_CREATE и WM_DESTROY Сообщение WM_CREATE передаётся при изначальном создании окна. Можно воспользоваться этим моментом и выполнить все необходимые задачи по инициализации (это официально принятая точка инициализации). Сообщение WM_DESTROY передаётся непосредственно перед уничтожением окна. Обычно оно означает, что приложение должно завершить работу. С этой целью вызывается функция PostQuitMessage . Она посылает сообщение WM_QUIT и завершает программу. Пример: case WM_DESTROY: PostQuitMessage(0); break; Учитывая выше изложенное оконная процедура может иметь следующий вид LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch(uMsg) { case WM_PAINT: hdc = BeginPaint(hWnd,&ps); GetClientRect(hWnd,&rect); DrawText(hdc,"Hello, world!",-1,&rect, DT_CENTER); EndPaint(hWnd,&ps); break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } В операционной системе Windows приложения, как правило, осуществляют вывод информации не напрямую на экран, а внутри своих окон. Такой способ организации графического вывода позволяет приложениям выводить информацию, не вступая в конфликт друг с другом. Приложение осуществляет графический вывод в окно в следующих случаях: • Непосредственно после создания и показа окна. • При изменении размеров окна. • При перемещении окна из-под вышестоящего окна. • При отображении данных (например, из открытого файла). • При изменении или выделении порции выводимой информации. Операционная система управляет такими действиями, как изменение размеров или перемещение окна. Если операция оказывает влияние на содержимое окна, то система помечает нужную область окна как нуждающуюся в перерисовке и посылает окну сообщение WM_PAINT . Это сообщение является сигналом для окна о необходимости обновления его содержимого. В ряде случаев необходимость перерисовки окна или его части может быть определена только самим приложением (например, в ответ на действия пользователя). В таких случаях приложение может самостоятельно пометить область окна как нуждающуюся в перерисовке, которая будет обновлена при следующей обработке сообщения WM_PAINT . Приложение также может выполнить немедленное обновление области окна, не дожидаясь получения следующего сообщения WM_PAINT Прежде чем выполнять графический вывод в окно, приложение должно получить дескриптор контекста устройства монитора для данного окна. Контекст графического устройства, имеющий тип HDC , задаёт набор графических объектов и их атрибутов, а также графических режимов, которые оказывают влияние на графический вывод. Подсистема Windows, отвечающая за графический вывод с использованием контекста устройства называется GDI – Graphic Device Interface. С её помощью приложения могут осуществлять графический вывод на любые графические устройства, такие как дисплей и принтер. При получении сообщения WM_PAINT , приложение должно вызвать функцию BeginPaint для получения дескриптора контекста устройства, связанного с клиентской областью окна, нуждающейся в перерисовке. После выполнения операций графического вывода приложение должно вызвать функцию EndPaint , для освобождения полученного таким образом дескриптора контекста устройства. В идеале, большую часть графического вывода окно должно осуществлять в обработчике сообщения WM_PAINT . Во всех остальных случаях (например при получении сообщения WM_SIZE ) для получения контекста устройства приложение должно использовать функцию GetDC , либо GetDCEx . В этом случае освобождение контекста выполняется при помощи функции ReleaseDC Windows GDI обеспечивает полный набор функций для форматирования и рисования текста в клиентской области окна или на бумажной странице принтера. Эти функции могут быть разделены на те, которые форматируют текст, подготавливая его для вывода, и те, которые действительно отображают текст. Форматирующие функции выравнивают текст, устанавливают межсимвольные промежутки, изменяют протяжённость разделительных символов, устанавливают цвет текста и цвет фона графических элементов. Рисующие функции выводят отдельные символы или целые строки текста. Простейшая функция вывода текстовой строки TextOut имеет следующий прототип: BOOL TextOut ( HDC hdc, // дескриптор контекста устройства int nXStart, // х-координата стартовой позиции int nYStart, // у-координата стартовой позиции LPCTSTR IpString, // указатель на символьную строку int cbString // число символов в строке ) ; Функция обеспечивает вывод строки с адресом IpString , размещая текст в заданной позиции с учётом текущего режима выравнивания. При выводе используются текущие значения атрибутов контекста устройства – шрифт, цвет текста и цвет фона графических элементов, режим смешивания фона и многие другие. Функция не распознаёт конец строки IpString по завершающему нулевому символу, поэтому количество выводимых символов задаётся параметром cbString . Символы строки должны входить в набор символов текущего шрифта. Позиционирование текста зависит от текущего режима выравнивания. Текущий режим выравнивания текста реализован как атрибут контекста устройства, определяющий правила позиционирования текста. Он указывает, что считать опорной точкой: точку с координатами nXStart и nYStart или текущую позицию пера в контексте устройства. Также режим выравнивания определяет, как позиционировать строку текста относительно опорной точки и как выводить текст: слева направо или справа налево. Ниже приведён пример использования функции TextOut char message[] = "Hello !"; TextOut(hdc, 0, 0, message, (sizeof(message) - 1)); В пользовательском интерфейсе Windows часто требуется вывести длинный текст в прямоугольнике, способном вместить несколько строк. Или, напротив, короткий текст поместить в прямоугольнике с учётом заданного позиционирования. Для решения подобных проблем GDI предоставляет функции DrawText и DrawTextEx Функция DrawText имеет следующий прототип: int DrawText( HDC hDC, // дескриптор контекста устройства LPCTSTR IpString, // указатель на текстовую строку int nCount, // длина текста LPRECT lpRect, // прямоугольник, в котором // размещается текст UINT uFormat / флаги форматирования ); Так же как и другие функции вывода текста, функция DrawText принимает в качестве параметров указатель на символьную строку и длину строки. Однако функция ведёт себя более интеллектуально по отношению к строкам с завершающим нулевым символом. Например, на месте параметра nCount можно передать значение -1, и функция сама определит длину строки. Если же строка не имеет завершающего нулевого символа, то правильнее будет указать её длину в аргументе nCount Функция DrawText выводит текстовую строку в прямоугольной области, заданной параметром LpRect . Последний параметр, uFormat , определяет метод форматирования текста. Его значение представляет собой битовую маску, образованную объединением флагов форматирования. Наиболее часто употребляемые флаги приведены в табл. 5. Если параметр uFormat имеет нулевое значение, то Windows интерпретирует текст как ряд строк, разделённых символами возврата каретки ( '\r' ) или символами конца строки ( '\n' ). Вывод текста производится, начиная с верхнего левого угла прямоугольника. Возврат каретки или конец строки воспринимаются как команда перейти на новую строку. Вывод новой строки начинается под предыдущей строкой с интервалом, равным высоте символа в строке. Таблица 5. Флаги форматирования для функции DrawText Значение Действие DT_LEFT Выравнивание текста влево DT_CENTER Центрирование по горизонтали DT_RIGHT Выравнивание текста вправо DT_TOP Начало размещения – в верхней части прямоугольника DT_VCENTER Центрирование по вертикали (используется только вместе с DT_SINGLELINE ) DT_BOTTOM Размещение внизу прямоугольника (используется только вместе с DT_SINGLELINE ) DT_WORDBREAK Перенос текста на следующую строку после окончания очередного слова, если оставшаяся часть текста не помещается по ширине прямоугольника вывода. Флаг работает, только если не указан флаг DT_SINGLELINE DT_SINGLELINE Вывод текста только в одну строку. Символы возврата каретки и перевода строки не воспринимаются как управляющие символы DT_EXPANDTABS Интерпретация символов \t как управляющих символов, задающих табуляцию. По умолчанию шаг табуляции равен восьмикратной средней ширине символов DT_NOPREFIX Отменяет обработку префиксов. Обычно DrawText интерпретирует префикс & как директиву «подчеркнуть следующий за префиксом символ», а последовательность && – как директиву вывести одиночный символ. С флагом DT_NOPREFIX символ & воспринимается наравне с другими символами, а не как префикс DT_PATH_ELIPPSIS Если строка не помещается по ширине прямоугольника, часть символов в середине строки замещается многоточием (используется только вместе с DT_SINGLELINE ) DT_END_ELIPPSIS Если строка не помещается по ширине прямоугольника, часть символов в конце строки замещается многоточием (используется только вместе с DT_SINGLELINE ) Любой текст, в том числе и части букв, попадающие при выводе правее или ниже границ прямоугольника, отсекаются. Можно предотвратить потерю текста от отсечения по правой границе, задав флаг DT_WORDBREAK Если выводится короткий текст, то рекомендуется указывать флаг DT_SINGLELINE . Это позволяет использовать все флаги позиционирования текста в прямоугольнике. В случае успешного завершения функция DrawText обычно возвращает высоту выведенного текста. Для многострочного текста возвращается суммарная высота всех строк. Исключение составляют случаи использования функции с флагом DT_CENTER или DT_BOTTOM . В этих двух случаях функция возвращает смещение нижней границы текста относительно верхней границы прямоугольника. Если функция по каким-либо причинам не смогла нормально выполнить свою работу, то возвращается нулевое значение. Система координат для окна базируется на координатной системе дисплея. Основной единицей измерения служит пиксел. Точки на экране задаются парой координат(х, у). При этом х-координаты возрастают слева направо, а y- координаты – сверху вниз. Расположение начала координат зависит от режима отображения. Позиция окна на экране задаётся в приложениях в экранных координатах, для которых началом координат является левый верхний угол экрана. Часто эта позиция описывается структурой типа RECT , содержащей экранные координаты левого верхнего угла и правого нижнего угла окна. Цвет пиксела можно рассматривать как некоторую точку в трёхмерном RGB-пространстве, образованном тремя цветовыми осями: Red (красная цветовая составляющая), Green (зелёная составляющая) и Blue (синяя составляющая). Система Windows поддерживает цветовое пространство RGB и пространство индексов палитры, соответствующее базовым возможностям видеоадаптера. Цвет кодируется в любом из этих пространств при помощи типа данных COLORREF , представляющего четырёхбайтное значение. Старший байт задаёт один из трёх возможных форматов: 0 – RGB , 1 – PALETTEINDEX , 2 – PALETTERGB Интерпретация формата RGB показана на рис. 1. Рис. 1. Тип данных COLORREF , формат RGB Минимальное значение (0) всех трёх составляющих цвета задаёт чёрный цвет. Максимальное значение (255) всех трёх составляющих цвета задаёт белый цвет. Комбинируя все возможные значения RGB-составляющих, можно получить 2 24 комбинаций, или примерно 16,7 миллиона возможных цветов. Windows API содержит несколько макросов, позволяющих объединять три составляющие RGB в одно 32-разрядное значение типа COLORREF либо, наоборот, разделять данные COLORREF на составляющие RGB-модели. Эти макросы, определённые в файле wingdi.h , можно представить в виде следующих подставляемых (inline) функций: COLORREF RGB(BYTE byRed, BYTE byGreen, BYTE byBlue); BYTE GetRValue(COLORREF rgb); BYTE GetGValue(COLORREF rgb); BYTE GetBValue(COLORREF rgb); Следующий фрагмент кода демонстрирует использование макроса RGB для определения констант, представляющих наиболее часто применяемые «чистые» цвета: const COLORREF black = RGB(0, 0, 0); const COLORREF red = RGB(255, 0, 0); const COLORREF green = RGB(0, 255, 0); const COLORREF blue = RGB(0, 0, 255); const COLORREF yellow = RGB(255, 255, 0); const COLORREF magenta = RGB(255, 0, 255); const COLORREF cyan = RGB(0, 255, 255); const COLORREF white = RGB(255, 255, 255); Для работы с пикселами предусмотрены следующие функции: COLORREF GetPixel(HDC hdc, int X, int Y); BOOL SetPixelV(HDC hdc, int X, int Y, COLORREF color); COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF color); Параметры X и Y определяют позицию пиксела в логических единицах. Параметр color , устанавливающий цвет пиксела, обычно задаётся при помощи макроса RGB Функция GetPixel возвращает цветовое значение пиксела с заданными координатами. Функции SetPixelV и SetPixel устанавливают заданное цветовое значение пиксела, различаясь возвращаемым значением. Первая функция возвращает логическое значение, указывающее, успешно ли прошла операция. Вторая функция в случае успешного выполнения возвращает старый цвет пиксела, а если произошла какая-то ошибка, то возвращается значение -1. GDI содержит набор графических объектов, обеспечивающих выполнение графических операций. К таким объектам относятся перья, кисти, растровые изображения, палитры, шрифты. Использование любого графического объекта предполагает выполнение следующей последовательности операций: 1. Создать графический объект. 2. Выбрать созданный объект в контекст устройства. 3. Вызвать графическую функцию, работающую с объектом. 4. Удалить объект из контекста устройства, вернув предшествующий объект. 5. Уничтожить объект. Для создания GDI-объектов предназначены соответствующие функции Create.. которые в случае успешного завершения возвращают дескриптор объекта. Выбор объекта в контекст устройства осуществляется при помощи функции SelectObject (палитры выбираются с помощью функции SelectPalette ). Функция SelectObject имеет следующий прототип: HGDIOBJ SelectObject( HDC hdc. // дескриптор контекста устройства HGDIOBJ hgdiobj // дескриптор GDI-объекта ) ; В результате её выполнения новый объект hgdiobj заменяет предшествующий объект того же типа в контексте устройства hdc Функция возвращает дескриптор предшествующего объекта. Для корректной работы приложение должно запомнить этот дескриптор и после окончания рисования с новым объектом вернуть в контекст устройства предшествующий объект. Для уничтожения объекта, ставшего ненужным, вызывается функция DeleteObject Для создания GDI-объекта не всегда нужно вызывать соответствующую функцию типа Create... . В системе имеется набор предопределённых (стандартных) графических объектов, и если параметры предопределённого объекта (перо, кисть, шрифт и т. д.) подходят для решаемой задачи, то приложение может получить такой объект с помощью функции |