47952 (597372), страница 3
Текст из файла (страница 3)
wc.style= CS_OWNDC;...
RegisterClass (&wc);...}
// при обработке сообщений в оконной функции:
LRESULT WINAPI _export WinProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{HDC hDC;
PAINTSTRUCT ps;
switch (wMsg) {
case WM_CREATE:...
hDC= GetDC (hWnd);
// ... установить атрибуты при создании окна
ReleaseDC (hWnd, hDC);...
break;
case WM_PAINT:
hDC= BeginPaint (hWnd, &ps);
// обычные функции получения хендла контекста устройства будут теперь
// возвращать хендл сохраненного контекста.
// здесь используются атрибуты, установленные ранее...
EndPaint (hWnd, &ps); // контекст по-прежнему должен быть освобожден
break;
case ...:...}
...}
Недостатком этого способа считается то, что каждое окно этого класса постоянно удерживает созданный контекст в памяти, что может быстро привести к использованию всех ресурсов компьютера.
В частном случае все окна одного класса могут иметь одинаковые атрибуты. Тогда можно указать стиль не CS_OWNDC, а CS_CLASSDC. Этот стиль указывает на то, что используется только одна сохраненная копия контекста в памяти, которая используется всеми окнами данного класса. В этом случае можно настраивать атрибуты контекста еще в функции WinMain, сразу после создания первого окна этого класса.
Системы координат GDI
Для начала надо уточнить то место, которое занимает система координат GDI в Windows. Как отмечалось при первом знакомстве, в Windows используется одновременно несколько разных систем координат. Среди них надо выделить следующие:
Система координат менеджера окон; в документации никак особо не оговаривается, что применяется именно эта система координат.
Система координат панели диалога; применяется только при разработке собственных диалогов. В тексте часто можно понять, что речь идет именно о ней, если оговаривается, что используются единицы диалога (dialog units). Если не оговаривается, то по контексту — все, связанное с шаблонами и ресурсами описания диалогов использует именно эту систему отсчета.
Система координат GDI; в документации координаты в системе координат GDI часто называют логическими координатами (logical coordinates). Там же может встретиться понятие координаты устройства (device coordinates).
Система координат GDI применяется при осуществлении графического вывода на устройство и, естественно, эта система координат определяется атрибутами контекста устройства. Таким образом для каждого контекста, существующего в настоящий момент, определяется собственная система координат.
Основные понятия
Вообще говоря, для задания любой системы координат необходимо как–то ее привязать к системе координат устройства (речь идет о системах координат, применяемых в Windows, а не о математическом понятии). Так, скажем, система координат менеджера окон отличается от системы координат устройства только лишь смещенным (а возможно и нет) началом отсчета — в верхний левый угол внутренней области окна.
Аналогично, система координат GDI тоже должна быть привязана к системе координат устройства. Точнее, она может быть привязана либо к системе координат устройства, если контекст соответствует всему устройству, либо к системе координат менеджера окон, если контекст соответствует окну.
В любом случае в Windows ту систему координат, по отношению к которой задается система координат GDI, называют системой координат устройства (device coordinates, viewport coordinates). А саму систему координат GDI называют логической системой координат (logical coordinates, window coordinates).
Обратите внимание, что английская терминология в этой области очень путаная, одно и то же понятие может обозначаться разными терминами даже в пределах одного абзаца. Так, термины viewport и device относятся к системе координат устройства, а термины logical и window описывают логическую систему координат. Это несколько странно, так как при выводе в окно система координат окна будет соответствовать координатам устройства, а логические координаты, используемые GDI, почему–то будут обозначаться термином window.
Когда система предоставляет вам контекст устройства, то его система координат совпадает с координатами устройства (окна), но у вас есть возможность эту систему координат самостоятельно изменить во время рисования на контексте.
Фактически логическая система координат определяется формулами, по которым происходит пересчет из логических координат в координаты устройства. При осуществлении вывода на контекст все координаты и размеры считаются заданными в логической системе координат, включая толщину проводимых линий, размеры шрифта, интервалы между символами, координаты точек и прочее.
В этих формулах используются нижние индексы в виде view и win, в соответствии с принятыми названиями атрибутов контекста устройства. Индекс view относится к системе координат устройства, а индекс win — к логической системе координат. То есть xview и yview — координаты какой–либо точки в системе координат устройства, Xview.org и Yview.org— относительное смещение начал отсчета систем координат, выраженное в единицах устройства (viewport origin), Xwin.org и Ywin.org — то же самое смещение, но выраженное в логических единицах (window origin), а Xview.ext, Yview.ext и Xwin.ext, Ywin.ext— масштабные коэффициенты (viewport extents, window extents).
Естественно, что в этих формулах смещение начала отсчета должно задаваться лишь единожды — либо для логической системы координат, либо для системы координат устройства. В каком именно виде — зависит исключительно от удобства. Например, если вы хотите начало отсчета логической системы координат поместить точно в центре окна (листа бумаги и пр.), то фактически вы знаете положение точки начала отсчета в координатах устройства — размеры контекста устройства, деленные пополам — тогда удобнее задать величины Xview.org и Yview.org, а Xwin.org и Ywin.org оставить равными нулю.
Рисунок 2. Система координат устройства и логическая система координат
Для обратного преобразования (из системы координат устройства в логическую систему координат), будут применяться такие же формулы, но с переставленными индексами win и view:
Иногда вам может понадобиться самим пересчитать координаты или размеры объекта из одной системы координат в другую. Вместо того, что бы самостоятельно использовать приведенные формулы, удобнее воспользоваться следующими функциями:
BOOL DPtoLP (hDC, lpPoints, nCount);
BOOL LPtoDP (hDC, lpPoints, nCount);
Функция DPtoLP преобразует координаты точек, заданных массивом lpPoints из nCount объектов типа POINT, заданные в системе координат устройства в логические координаты (DPtoLP — Device Point to Logical Point), то есть из «view» в «win» , а функция LPtoDP — выполняет обратное преобразование.
Под координатами устройства может подразумеваться либо непосредственно система координат устройства, если контекст соответствует всему устройству, либо система координат, связанная с окном, если контекст соответствует внутренней или внешней области окна. Так, при выводе в окно, реальное положение какой–либо точки окна на экране может быть вычислено в два этапа — сначала с помощью функции LPtoDP надо пересчитать логические координаты в координаты, связанные с окном, а затем с помощью функции ClientToScreen пересчитать из координат окна в координаты экрана. При работе с устройством в целом, например при выводе на принтер, достаточно одной функции LPtoDP.
При использовании функций DPtoLP и LPtoDP возможно возникновение интересных ошибок. Представим себе, например, что вам надо нарисовать линию шириной 10 пиксель. Так как логическая система координат может не совпадать с координатами устройства, то линия шириной 10 логических единиц вовсе не обязательно будет шириной 10 пиксель. Само собой напрашивается примерно такой фрагмент программы для вычисления ширины линии:
POINT pt;
pt.x = 10; pt.y = 0;
DPtoLP (hdc, &pt, 1); // пересчитаем 10 пиксель (ед. устройства) в логические
// единицы. Далее считаем, что в компоненте pt.x записана нужная нам величина
Ошибка, которая присутствует в этом фрагмента, сразу и не видна. Более того, во многих случаях вы получите вполне приемлемый результат и даже не заподозрите об ошибке — до тех пор, пока у вашей логической системы координат не окажется смещенным начало отсчета по оси x от левой границы контекста. В этом случае вы получите ширину 10 пиксель, преобразованную в логические единицы плюс смещение начала отсчета:
Рисунок 3. Из–за смещения начала отсчета возможно возникновение ошибок.
Что бы избежать подобной ошибки лучше брать не одну точку, а вектор нужной длины:
POINT vector[ 2 ];
vector[0].x = 0; vector[0].y = 0;
vector[1].x = 10; vector[1].y = 0;
DPtoLP (hdc, &vector, 2);
vector[1].x -= vector[0].x;
// Далее считаем, что в компоненте vector[1].x записана нужная нам величина
Выбор системы координат
Для описания используемой системы координат предназначено пять атрибутов контекста устройства. Четыре атрибута описывают смещение начала отсчета и масштабные коэффициенты. Пятый атрибут — собственно выбранная в настоящий момент система координат.
| Название атрибута | Значение по умолчанию | Обозначение в формулах | |
| Mapping mode | Система координат | MM_TEXT | |
| Window origin | Начало отсчета в логических координатах | 0,0 | Xwin.org, Ywin.org |
| Viewport origin | Начало отсчета в координатах устройства | 0,0 | Xview.org, Yview.org |
| Window extents | Масштабные коэффициенты системы координат | 1,1 | Xwin.ext, Ywin.ext |
| Viewport extents | Масштабные коэффициенты системы координат | 1,1 | Xview.ext, Yview.ext |
Стандартная система координат GDI, выбираемая в контекст устройства при его создании совпадает с системой координат самого устройства (или окна). Такая система координат получила название текстовой (MM_TEXT). Вы можете отказаться от этой системы координат и установить некоторую собственную систему, у которой ориентация осей или масштабные коэффициенты отличаются от стандартной. Очевидно, что чаще всего придется устанавливать какие–либо системы координат, базирующиеся на метрической или английской системах мер. Раз так, то Microsoft предоставляет несколько дополнительных систем координат, так что во многих случаях вы можете просто выбрать подходящую вам метрическую (MM_LOMETRIC, MM_HIMETRIC), английскую систему (MM_LOENGLISH, MM_HIENGLISH) или полиграфическую (MM_TWIPS), не заботясь о точном вычислении масштабных коэффициентов. Более того, используя какую–либо из вышеназванных систем вы вообще не можете изменять масштабные коэффициенты, хотя можете перемещать точку начала отсчета.
В тех же случаях, когда вы хотите самостоятельно настраивать масштабные коэффициенты, вы можете воспользоваться системой координат MM_ANISOTROPIC, в которой вы свободно можете менять все коэффициенты, либо MM_ISOTROPIC, в которой GDI позволит вам произвольно назначать масштабные коэффициенты, но при этом сам их скорректирует, так что масштаб по обеим осям окажется равным. То есть если вы нарисуете прямоугольник с равным логическим размером сторон, то на рисунке он будет выглядеть квадратом.
| Название | Единица | Ориентация осей |
| MM_TEXT | 1 пиксель | |
| MM_LOMETRIC | 0.1 мм | |
| MM_HIMETRIC | 0.01 мм | |
| MM_LOENGLISH | 0.01" | |
| MM_HIENGLISH | 0.001" | |
| MM_TWIPS | 1/20 полиграфической точки = 1/1440" (предполагается, что полиграфическая точка = 1/72")2 | |
| MM_ISOTROPIC | x=y цена единицы определяется пользователем | |
| MM_ANISOTROPIC | x!=y цена единицы определяется пользователем | |
Обратите внимание, что при выборе любой системы координат начало отсчета размещается в верхнем левом углу контекста, даже если ось Y направлена вверх (!). При этом получается, что весь рисунок располагается в области отрицательных значений координаты Y. На практике это значит, что для большинства систем координат (кроме MM_TEXT и MM_TWIPS) вы как правило должны задать новое положение начала отсчета.














