MARK : Windows 程序设计
这部分我从Windows 程序设计中单独摘出来,方便查看 !!!
使用映像模式 :
SetMapMode(hdc, iMapMode);
iMapMode = GetMapMode(hdc);
映像模式就是进行一种将 逻辑 单位 转换为 设备 单位 的规则的设定 。
设备坐标和逻辑坐标 :
Windows 对所有消息(如WM_MOUSEMOVE, WM_SIZE, WM_MOVE),对所有非 GDI 函数,甚至是一些 GDI 函数 , 永远使用设备坐标 。 可 以这样来考虑:由于映像方式是一种设备内容属性,所以,只有对需要设备内容句柄作参数的GDI函数,映像方式才会起作用。 GetSystemMetrics不是GDI函数,所以它总是以设备单位(即像素)为量度来传回大小的。尽管GetDeviceCaps是GDI函数,需 要一个设备内容句柄作为参数,但是Windows仍然对HORZRES和VERTRES以设备单位作为传回值,因为该函数的目的之一就是给程序提供以像素 为单位的设备大小。
从GetTextMetrics呼叫中传回的TEXTMETRIC结构的值是使用 逻辑单位 的 。如果在进行此呼叫时映像方式为MM_LOENGLISH,则GetTextMetrics将以百分之一英寸为单位提供字符的宽度和高度。
设备坐标系 :
所有设备坐标系都是以 像素为单位 ,x轴从左到右递增,y轴从上到下递增。
屏幕坐标系 :(第一种设备坐标)
当我们使用整个屏幕时,就根据“屏幕坐标”进行操作。 屏幕的左上角为 (0, 0)点 , 屏幕坐标用在WM_MOVE 以及下列函数中 CreateWindow ,MoveWindow(都是非子窗口),GetMessagePos,GetCursorPos,SetCursorPos,GetWindowRect,WindowFromPoint。
全窗口坐标系 :(第二种设备坐标)
“全窗口坐标”以程序的整个窗口为基准,标题栏,菜单,滚动条,窗口显示区域,都包括在内,对于普通窗口, 点 (0, 0) 是非显示区域的左上角 ,全窗口坐标在Windows 中极少使用,如果用GetWindowDC 取得设备内容,GDI 函数中的逻辑坐标就会转化为“全窗口坐标”。
显示区域坐标系 :(第三种设备坐标)
“显示区域坐标系”, 点 (0, 0) 式显示区域的左上角 ,使用 GetDC 或者 BeginPaint 获得的 hdc 时, GDI 函数中的逻辑坐标就会转化为 “显示区域坐标”;
用函数 ClientToScreen 和 ScreenToClient 可以将 显示区域坐标和屏幕坐标互相转换 。可以使用 GetWindowRect 函数获得屏幕坐标下的整个窗口的位置和大小。
视口,窗口,设备,逻辑 :
窗口 坐标系 与逻辑 坐标 ,它们的单位是一样的,都是逻辑单位,但是他们二者是不同的,我们 通常输入的坐标就是逻辑坐标 ,但是输入之后,如何显示在屏幕上的对应位置?视口 坐标系 与设备 坐标系 ,它们的单位也是一样的,都是像素,但是他们二者也是不同的,所有显示在屏幕上的东西都是以设备坐标系去输出,因为 设备坐标是永远固定的,它的(0, 0)点始终是在 hdc 所对应的左上角 。这其实也就是为什么 Windows 对所有消息(如WM_MOUSEMOVE, WM_SIZE, WM_MOVE),对所有非 GDI 函数,甚至是一些 GDI 函数, 永远使用设备坐标 的原因。看下面四者之间的关系:
DPtoLP(hdc, &pt, 1); // 设备坐标转换为逻辑坐标
LPtoDP(hdc, &pt, 1); // 逻辑坐标转换为设备坐标
需要注意的是 第二个参数, 是 in/out 类型参数,也就是输入输出都是这个参数。
BOOL SetWindowOrgEx (
HDC hdc, // handle to device context
int X, // new x-coordinate of window origin // 这是逻辑坐标
int Y, // new y-coordinate of window origin // 这是逻辑坐标
LPPOINT lpPoint // original window origin
);
The SetWindowOrgEx function specifies which window point maps to the viewport origin (0,0) .
指定窗口坐标原点,而且这个原点是相对于视口坐标原点的。
@font-face{ font-family:"times new roman"; } @font-face{ font-family:"宋体"; } @font-face{ font-family:"symbol"; } @font-face{ font-family:"arial"; } @font-face{ font-family:"黑体"; } @font-face{ font-family:"courier new"; } @font-face{ font-family:"wingdings"; } @font-face{ font-family:"courier new cyr"; } p.0{ margin:0pt; margin-bottom:0.0001pt; layout-grid-mode:char; text-align:justify; font-size:10.5000pt; font-family:'times new roman'; } div.section0{ margin-top:72.0000pt; margin-bottom:72.0000pt; margin-left:90.0000pt; margin-right:90.0000pt; size:612.0000pt 792.0000pt; }
BOOL OffsetWindowOrgEx ( //在原来窗口原点的基础上 偏移窗口原点
HDC hdc, // handle to device context
int nXOffset, // horizontal offset
int nYOffset, // vertical offset
LPPOINT lpPoint // original origin
);
BOOL SetViewportOrgEx (
HDC hdc, // handle to device context
int X, // new x-coordinate of viewport origin // 这是逻辑坐标
int Y, // new y-coordinate of viewport origin // 这是逻辑坐标
LPPOINT lpPoint // original viewport origin
);
The SetViewportOrgEx function specifies which device point maps to the window origin (0,0).
指定视口坐标原点,而且这个原点是相对于窗口坐标原点的。
GetWindowOrgEx(hdc, &pt); //获得窗口坐标原点【逻辑坐标】
GetViewportOrgEx(hdc, &pt); //获得视口坐标原点【逻辑坐标】
使用SetMapMode 能改变 hdc 对应设备内容的属性,每次输出看当前的映射模式。
MM_ISOTROPIC 映像方式 :
这种映像方式,可以使用 SetWindowExtEx 和 SetViewportExtEx 来根据自己的偏好改变范围,默认的范围和 MM_LOMETRIC相同。设定示例如下:
rect.right = 300;
rect.bottom = 280;
FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
SetMapMode (hdc, MM_ISOTROPIC);
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, 300, 280, NULL);
rect.right = 280;
rect.bottom = 280;
FillRect(hdc, &rect, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
TextOut(hdc, 100, 100, TEXT("HHHHHHHHH"), lstrlen(TEXT("HHHHHHHHH")));
效果如下:
详解 :
默认的Viewport 的范围是 (cxScreen,cyScreen),所以,为了能正常在程序的显示区域显示我们的输出,通常将其设定为 (cxClient,cyClient)。MM_ISOTROPIC 模式下 Windows会调整范围,以便两条轴上的逻辑单位具有相同的实际尺度,所以上面才出现了一个20px 的未被使用的区域。
有的人不习惯左上角为(0, 0),喜欢左下角为(0, 0),那么你就可以做如下设定:
RECT rect;
GetClientDC(hdc, &rect);
SetMapMode(hdc, MM_ ISOTROPIC );
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, rect.right, -rect.bottom , NULL);
//负值表示的范围大小区域位置都不变 ,只是区域内, x 或者 y 轴的方向改变了 。
SetViewportOrgEx(hdc, 0, rect.bottom, NULL);
这样就能得到一个和常用的坐标系一样的坐标系。
MM_ANISOTROPIC :根据需要放缩图像
在MM_ANISOTROPIC映射方式下,Windows不对您所设定的值进行调整,这就是说,MM_ANISOTROPIC不需要维持 1:1 的纵横比。
第 一次设定MM_ANISOTROPIC映像方式时,它总是继承前面所设定的映像方式的范围,这会很方便。例如,假设您想用MM_LOENGLISH映像方 式,因为希望逻辑单位为0.01英寸,但您不希望y轴的值向上增加,喜欢如MM_TEXT那样的方向,即y轴的值向下增加,可以使用如下的代码:
SIZE size;
SetMapMode(hdc, MM_LOENGLISH); //给定ANISOTROPIC 范围
SetMapMode(hdc, MM_ANISOTROPIC);
GetViewportExtEx(hdc, &size);
SetViewportExtEx(hdc, size.cx, -size.cy , NULL);