Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

100

Переменная logbrush имеет тип структуры LOGBRUSH "логическая кисть" (logical brush). Ниже приведены три поля этой структуры. Значение поля lbStyle определяет, как Windows будет интерпретировать два других поля:

lbStyle (UINT)

lbColor (COLORREF)

lbHatch (LONG)

BS_SOLID

Цвет кисти

Игнорируется

BS_HOLLOW

Игнорируется

Игнорируется

BS_HATCHED

Цвет штриховых линий

Стиль штриховки

BS_PATTERN

Игнорируется

Описатель битового шаблона

Раньше мы использовали функцию SelectObject для выбора логического пера в контекст устройства, функцию DeleteObject — для удаления логического пера, и функцию GetObject — для получения информации о логическом пере. Вы можете использовать эти же три функции применительно к кистям. Получив описатель логической кисти, вы можете выбрать ее в контекст устройства, используя SelectObject:

SelectObject(hdc, hBrush);

Позднее вы удалите созданную кисть с помощью функции DeleteObject:

DeleteObject(hBrush);

Но никогда не удаляйте кисть, установленную текущей в контексте устройства. Если вам нужна информация о кисти, вы можете вызвать GetObject:

GetObject(hBrush, sizeof(LOGBRUSH),(LPVOID) &logbrush);

В этом вызове logbrush — это структура типа LOGBRUSH.

Режим отображения

До сих пор предполагалось, что мы рисуем в пиксельных координатах с началом координат в левом верхнем углу рабочей области окна. Да, это так по умолчанию, но это не единственная возможность.

Один из атрибутов контекста устройства, который фактически влияет на все, что вы рисуете в рабочей области, это режим отображения (mapping mode). Четыре других атрибута контекста устройства — начало координат окна

(window origin), начало координат области вывода (viewport origin), протяженность окна (window extents) и

протяженность области вывода (viewport extents) — полностью зависят от значения атрибута режима отображения.

Большинство рисующих функций GDI требуют в качестве параметров координаты или размеры. Например, функция TextOut:

TextOut(hdc, x, y, szBuffer, iLength);

Параметры x и y задают начальную позицию текста. Параметр x — это горизонтальная позиция, а параметр y — вертикальная позиция. Часто запись (x, y) используется для указания этой точки.

Вфункции TextOut, как фактически во всех функциях GDI, эти значения координат задаются в "логических единицах измерения". Windows должна преобразовать логические единицы в "физические единицы, единицы измерения устройства", т. е. пиксели. Результат этого преобразования определяется режимом отображения, началом координат окна и области вывода, растяжением окна и области вывода. Режим отображения задает также направление осей координат x и y, т. е. определяет, в каком направлении на экране возрастает значение координаты x — влево или вправо и в каком направлении возрастает значение координаты y — вверх или вниз.

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

Режим

Логические

Направление увеличения

отображения

единицы

 

 

ось x

ось y

MM_TEXT

Пиксели

вправо

вниз

MM_LOMETRIC

0.1 мм

вправо

вверх

MM_HIMETRIC

0.01

мм

вправо

вверх

MM_LOENGLISH

0.01

дюйма

вправо

вверх

MM_HIENGLISH

0.001 дюйма

вправо

вверх

MM_TWIPS*

1/1440 дюйма

вправо

вверх

MM_ISOTROPIC

Произвольные (x=y)

выбирается

выбирается

* Слово "twip" производное от "twentieth of a point" — одна двадцатая часть точки. Точка, как единица измерения, равна примерно 1/72 дюйма, однако часто в графических системах таких как GDI, считается точно равной 1/72 дюйма. Twip — это 1/20 точки и, следовательно, 1/1440 дюйма.

101

Режим

Логические

Направление увеличения

отображения

единицы

ось x

ось y

MM_ANISOTROPIC

Произвольные (x!=y)

выбирается

выбирается

Вы можете устанавливать режим отображения, используя функцию:

SetMapMode(hdc, iMapMode);

Параметр iMapMode — это один из восьми идентификаторов режима отображения. Определить текущий режим отображения вы можете путем вызова:

iMapMode = GetMapMode(hdc);

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

TextOut(hdc, 8, 16, szBuffer, iLength);

текст начинается в точке, отстоящей на 8 пикселей слева и на 16 пикселей сверху от границы рабочей области. Если установлен режим отображения MM_LOENGLISH, то логические единицы — это сотые доли дюйма:

SetMapMode(hdc, MM_LOENGLISH);

Теперь вызов функции TextOut может выглядеть так:

TextOut(hdc, 50, -100, szBuffer, iLength);

Текст начинается на расстоянии 0,5 дюйма от левого края и на расстоянии 1-го дюйма от верхнего края рабочей области. (Почему у координаты y стоит знак минус, станет понятно позже, когда режимы отображения будут рассматриваться более подробно.) Другие режимы отображения позволяют программе задавать координаты вывода в миллиметрах, размерах точки принтера или произвольных единицах.

Если вы чувствуете себя уверенно при работе с пикселями, то вам не нужно использовать другие, отличные от MM_TEXT, режимы отображения. Если же вы хотите рисовать образы в реальных единицах измерения, таких как миллиметры или дюймы, то вы можете получить нужную вам информацию из функции GetDeviceCaps и осуществлять свое собственное масштабирование. Другие режимы отображения просто освобождают вас от этой рутинной работы.

Независимо от режима отображения все координаты, которые вы задаете в функциях Windows, должны быть знаковыми короткими целыми (signed short integer) числами в интервале от —32768 до 32767. Некоторые функции Windows, использующие начальную и конечную точки прямоугольника, также требуют, чтобы ширина и высота прямоугольника были меньше чем 32767.

Координаты устройства (физические координаты) и логические координаты

Вы можете спросить: если использовать режим отображения MM_LOENGLISH, можно ли получать сообщения WM_SIZE в терминах сотых долей дюйма? Конечно, нет. Windows продолжает использовать координаты устройства для всех сообщений (таких как WM_MOVE, WM_SIZE и WM_MOUSEMOVE), для всех функций, не принадлежащих GDI, и даже для некоторых функций GDI. Посмотрите на это с такой точки зрения: режим отображения — это атрибут контекста устройства, поэтому он начинает работать только тогда, когда вы используете функции GDI, требующие передачи им описателя контекста устройства. GetSystemMetrics — не является функцией GDI, следовательно, она будет продолжать возвращать размеры в координатах устройства, т. е. в пикселях. И хотя функция GetDeviceCaps — функция GDI и требует описателя контекста устройства, Windows продолжает возвращать единицы измерения устройства для индексов HORZRES и VERTRES, поскольку одна из задач этой функции — дать программе сведения о размерах устройства в пикселях.

Тем не менее, величины в структуре TEXTMETRIC, которую можно получить из функции GetTextMetrics, задаются в логических координатах. В режиме отображения MM_LOENGLISH функция GetTextMetrics возвращает информацию о ширине и высоте символов в сотых долях дюйма. Когда вы вызываете функцию GetTextMetrics для получения информации о ширине и высоте символов, режим отображения должен быть установлен таким, каким он будет, когда вы вызовите функцию рисования, использующую эти размеры. Поскольку в этой главе рассматриваются различные функции GDI, ваше внимание будет обращаться на то, какие координаты они используют — логические или физические. Все функции, которые мы рассматривали до сих пор, используют логические координаты, за исключением тех, которые определяют закрашивание пустот между точками и штрихами в линиях, и между штрихами в штриховых шаблонах. Работа этих функций не зависит от режима отображения.

102

Системы координат устройства

Windows преобразует логические координаты, заданные в функциях GDI, в координаты устройства. Перед тем, как мы рассмотрим логические системы координат, используемые в различных режимах отображения, давайте разберемся с системой координат устройства, которую Windows определяет для экрана дисплея. Хотя мы работали в основном с рабочей областью окна, Windows использует еще два других пространства координат устройства в разные моменты времени. Во всех системах координат устройства единицами всегда считаются пиксели. Значения горизонтальной координаты x возрастает слева направо, значения вертикальной координаты y — сверху вниз.

Когда мы работаем с экраном целиком, мы работаем в терминах "экранных координат." Левый верхний угол экрана — точка (0, 0). Экранные координаты используются в сообщениях WM_MOVE (для окон верхнего уровня, не дочерних) и в следующих функциях Windows: CreateWindow и MoveWindow (обе для не дочерних окон),

GetMessagePos, GetCursorPos, SetCursirPos, GetWindowRect, WindowFromPoint и SetBrushOrgEx. Эти функции, в

основном, не имеют окна, ассоциированного с ними (например, две функции работы с курсором), или функции, которые должны переместить или найти окно на основе положения некоторой точки экрана. Если вы используете функцию CreateDC с параметром DISPLAY для получения контекста устройства всего экрана, то логические координаты, указанные в вызовах функций GDI, будут преобразованы в координаты устройства.

"Полные координаты окна" (whole-window coordinates) определяют окно программы целиком, включая заголовок, меню, полосы прокрутки и рамку. Для обычного окна точка (0, 0) — левый верхний угол рамки окна. Полные координаты окна редко используются в Windows, но если вы получите контекст устройства, используя функцию GetWindowDC, то логические координаты в вызовах функций GDI будут преобразовываться в координаты всего окна.

Третья система координат устройства — это та, с которой мы работали больше всего, — система координат рабочей области окна. Точка (0, 0) — верхний левый угол рабочей области окна. Когда вы получаете контекст устройства, используя функции GetDC или BeginPaint, логические координаты в вызовах функций GDI преобразуются в координаты рабочей области окна.

Вы можете конвертировать координаты рабочей области окна в координаты экрана и наоборот, используя функции ClientToScreen и ScreenToClient. Вы можете также получить местоположение и размеры окна целиком в экранных координатах, используя функцию GetWindowRect. Эти три функции предоставляют достаточно возможностей для любых преобразований координат.

Область вывода и окно

Режим отображения определяет, как Windows преобразует логические координаты, заданные в параметрах функций GDI, в координаты устройства, конкретная система координат которого зависит от того, какой функцией вы получили контекст устройства. Для дальнейшего рассмотрения режимов отображения нам необходимо определить некоторые дополнительные термины: Говорят, что режим отображения определяет преобразование "окна" (window) — логические координаты, в "область вывода" (viewport) — координаты устройства.

Использование слов "окно" и "область вывода" не совсем удачно. В других языках графического интерфейса "область вывода" часто определяется как "область отсечения" (clipping region). Мы использовали термин "окно", имея в виду область экрана, захваченную программой. Мы должны оставить в стороне наше предвзятое мнение об этих терминах на время обсуждения.

Область вывода описывается в терминах координат устройства (пикселях). Чаще всего область вывода — это то же самое, что и рабочая область, хотя область вывода может описываться также и в полных координатах окна или в координатах экрана, если вы получили контекст устройства из функций GetWindowDC или CreateDC. Точка (0, 0)

— левый верхний угол рабочей области (или окна целиком, или всего экрана). Значения координаты x возрастают слева направо, а значения координаты y — сверху вниз.

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

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

xViewport = (xWindow — xWinOrg) × (xViewExt/xWinExt) + xViewOrg yViewport = (yWindow — yWinOrg) × (yViewExt/yWinExt) + yViewOrg,

где (xWindow, yWindow) — логическая точка для преобразования, (xViewport, yViewport) — преобразованная точка в координатах устройства. Если координаты устройства — это координаты рабочей области или окна целиком, то Windows должна также преобразовать их в координаты экрана перед выводом объекта.

Эти формулы используют две точки, задающие начала координат (origin) окна и области вывода: (xWinOrg, yWinOrg) — начало координат окна в логических координатах; (xViewOrg, yViewOrg) — начало координат области

103

вывода в координатах устройства. В контексте устройства, установленном по умолчанию, обе эти точки установлены в точку (0, 0), но они могут быть изменены. Эти формулы гарантируют, что точка с логическими координатами (xViewOrg, yViewOrg) всегда преобразуется в точку с физическими координатами (xViewOrg, yViewOrg).

Эти формулы используют также две точки, определяющие "протяженность" (extent): (xWinExt, yWinExt) — протяженность окна в логических координатах; (xViewExt, yViewExt) — протяженность области вывода в координатах устройства. В большинстве режимов отображения протяженности определяются самими режимами и не могут быть изменены. Каждая протяженность сама по себе ничего не значит. Только отношение протяженности области вывода к протяженности окна является коэффициентом масштабирования при пересчете логических координат в координаты устройства. Протяженность может быть отрицательной. Это означает, что величина логической координаты x не обязательно должна возрастать при перемещении вправо, а величина логической координаты y — необязательно возрастать при движении вниз.

Windows может также преобразовывать координаты устройства (физические) в координаты окна (логические): xWindow = (xViewport — xViewOrg) × (xWinExt/xViewExt) + xWinOrg

yWindow = (yViewport — yViewOrg) × (yWinExt/yViewExt) + yWinOrg

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

DPtoLP(hdc, pPoints, iNumber);

Переменная pPoints — это указатель на массив структур типа POINT, iNumber — число преобразуемых точек. Вы обнаружите, что эта функция очень полезна для преобразования размера рабочей области, полученного от функции GetClientRect (которая всегда оперирует с координатами устройства), в логические координаты:

GetClientRect(hwnd, &rect);

DPtoLP(hdc,(PPOINT) &rect, 2);

Следующая функция преобразует логические точки в физические точки:

LPtoDP(hdc, pPoints, iNumber);

Работа в режиме MM_TEXT

В режиме MM_TEXT заданы следующие величины начал координат и протяженностей:

Начало координат окна: (Window origin)

(0, 0)

Может быть изменено

Начало координат области вывода: (Viewport origin)

(0, 0)

Может быть изменено

Протяженность окна: (Window extent)

(1, 1)

Не может быть изменена

Протяженность области вывода: (Viewport extent)

(1, 1)

Не может быть изменена

Отношение протяженности области вывода к протяженности окна равно 1, таким образом, масштабирование

между логическими и физическими координатами не производится. Формулы, приведенные выше, принимают

вид:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

xViewport = xWindow — xWinOrg + xViewOrg

 

 

 

 

 

 

 

 

yViewport = yWindow — yWinOrg + yViewOrg

 

 

 

 

+X

 

 

 

 

 

 

 

 

 

 

Этот режим отображения называется "текстовым" не потому, что он

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

наиболее удобен для вывода текста, а из-за направления осей координат.

 

 

 

 

 

 

 

 

 

 

+Y

 

 

 

 

 

Мы читаем текст слева направо и сверху вниз, и MM_TEXT аналогично

 

 

 

 

 

 

 

 

 

 

 

 

задает направления увеличения координат:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Windows имеет функции SerViewportOrgEx и SetWindowOrgEx для

изменения начала координат области вывода и окна. Эти функции обладают эффектом сдвига осей координат таким образом, что логическая точка (0, 0) не будет далее соответствовать левому верхнему углу рабочей области. Чаще всего вы будете использовать SetViewportOrgEx или SetWindowOrgEx, но не обе функции одновременно.

Вот как работают эти функции. Если вы переносите начало координат области вывода в точку (xViewOrg, yViewOrg), то логическая точка (0, 0) будет соответствовать физической точке с координатами (xViewOrg, yViewOrg). Если вы переносите начало координат окна в точку (xWinOrg, yWinOrg), то логическая точка (xWinOrg, yWinOrg) будет соответствовать физической точке с координатами (0, 0), т. е. левому верхнему углу рабочей области.

104

Например, предположим, что рабочая область вашего окна имеет ширину cxClient и высоту cyClient пикселей. Если вы хотите установить начало логической системы координат — точку (0, 0) — в центр рабочей зоны окна, вы можете это сделать так:

SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

—Y

 

 

Аргументы функции SetViewportOrgEx всегда задаются в координатах устройства.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Логическая точка (0, 0) будет теперь отображаться в точку с физическими

 

 

 

 

 

 

 

 

 

 

 

координатами (cxClient/2, cyClient/2). Теперь вы используете рабочую область так,

 

 

 

 

 

 

+X

 

 

 

—X

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

как будто бы она имела представленную ниже систему координат:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Значения логической координаты x могут изменяться в диапазоне от —cxClient/2 до

 

 

 

 

 

 

 

 

 

 

 

cxClient/2. Значения логической координаты y могут изменяться в диапазоне от

 

 

 

 

 

+Y

 

 

 

 

 

 

 

 

 

 

 

 

cyClient/2 до cyClient/2. Правый нижний угол рабочей области — точка с

 

 

 

 

 

 

 

 

 

 

 

логическими координатами (cxClient/2, cyClient/2). Если вы хотите вывести текст, начиная от верхнего левого угла рабочей зоны, имеющего физические координаты (0, 0), вам необходимо задать отрицательные координаты:

TextOut(hdc, -cxClient / 2, -cyClient / 2, "Hello", 5);

Вы можете добиться того же результата, используя функцию SetWindowOrgEx вместо функции SetViewportOrgEx:

SetWindowOrgEx(hdc, -cxClient / 2, -cyClient / 2, NULL);

Аргументы функции SetWindowOrgEx всегда задаются в логических координатах. После этого вызова логическая точка (—cxClient/2, —cyClient/2) соответствует физической точке (0, 0) — левому верхнему углу рабочей области.

То, чего вы не должны делать (до тех пор, пока вы не будете знать, к чему это приведет) — это использовать обе функции совместно:

SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);

 

 

 

 

 

 

SetWindowOrgEx(hdc, -cxClient / 2, -cyClient / 2, NULL);

 

 

 

 

 

 

 

 

 

—Y

 

 

 

 

 

 

 

 

Это означает, что логическая точка (—cxClient/2, —cyClient/2) соответствует

 

 

 

 

 

 

 

 

 

 

 

 

физической точке (cxClient/2, cyClient/2), представляя вам такую систему координат:

 

 

 

 

 

 

Вы можете получить текущее положение начала координат области вывода и окна,

 

—X

 

 

 

 

 

 

 

 

 

 

используя функции:

 

 

 

 

 

 

 

 

 

 

 

 

GetViewportOrgEx(hdc, &pt);

 

 

 

 

 

 

 

 

 

 

 

 

GetWindowOrgEx(hdc, &pt);

где pt — структура типа POINT (точка).

Функция GetViewportOrgEx возвращает значение в координатах устройства, а функция GetWindowOrgEx — в логических координатах.

Вы можете изменить начала координат области вывода и окна так, чтобы сдвинуть экранный вывод в рабочую зону вашего окна — например, в ответ на изменение пользователем состояния полосы прокрутки. Изменение начала координат области вывода или окна не приводит к немедленному сдвигу экранного вывода. Например, в программе SYSMETS2 из главы 2 мы использовали значение iVscrollPos (текущее положение вертикальной полосы прокрутки) для вычисления соответствующей координаты y экранного вывода:

case WM_PAINT : BeginPaint(hwnd, &ps);

for (i = 0; i < NUMLINES; i++)

{

y = cyChar *(1 — iVscrollPos + i); [вывод текста]

}

EndPaint(hwnd, &ps); return 0;

Мы можем добиться того же результата, используя функцию SetWindowOrgEx:

case WM_PAINT : BeginPaint(hwnd, &ps);

SetWindowOrgEx(ps.hdc, 0, cyChar * iVscrollPos);

for (i = 0; i < NUMLINES; i++)

{

Соседние файлы в предмете Операционные системы