Windows 映射模式
I_Love_CPP
(电子科技大学)
注:版权所有!如果要刊登、转载请给稿费!!!
联系方式: I.Love.Cpp@126.com
一、 映射模式
这是一个初级话题,但好像很多人都没有弄明白,因为几乎每过几天就用人发帖问这个。半年前有人问我这个问题时就想写这篇文章了,但一直觉得没有时间(因为除了学习、工作和玩耍,几乎就没有多少空时间了)。本文现在其实只能算着《 Programming Windows 》中关于“映射模式”的加工,以咱们中国读者更易懂的方式写出;我将逐步往其中添加一些相关内容。
首先,从一个十分简单但又很常用的函数开始:
BOOL TextOut( HDC hdc , // handle to DC
int nXStart , // x-coordinate of starting position
int nYStart , // y-coordinate of starting position
LPCTSTR lpString , // character string
int cbString // number of characters );
这里的( nXstart , nYStart )是字符串显示的起始坐标点,这里的坐标就是“逻辑坐标”。为了最终将文字显示到设备(屏幕)上, Windows 必须将这些逻辑坐标“翻译”成“设备坐标” —— 其实就是“像素 (pixels) ”。 Windows 一共定义了 8 种映射模式,如下表所示:
-----------------------------------------------------------------------------------
Increasing Value
Mapping Mode Logical Unit x-axis y-axis
MM_TEXT Pixel Right Down
MM_LOMETRIC 0.1 mm Right Up
MM_HIMETRIC 0.01 mm Right Up
MM_LOENGLISH 0.01 in. Right Up
MM_HIENGLISH 0.001 in. Right Up
MM_TWIPS 1/1440 in. Right Up
MM_ISOTROPIC Arbitrary (x = y) Selectable Selectable
MM_ANISOTROPIC Arbitrary (x !=y) Selectable Selectable
--------------------------------------------------------------------------------------
表 1
注: in. 表 英寸 ; Windows 默认的映射模式是 MM_TEXT ,其实就是 设备坐标 !!!
趁热打铁,看一下例子:
例: 如果我们没有用 SetMapMode 设定 Windows 的映射模式,那么 Windows 将使用默认的 MM_TEXT 映射模式,
TextOut (hdc, 8, 16, TEXT ("Hello"), 5);
的结果是文字将从离客户区左边界 8 个像素、离上边界 16 个像素的位置从左向右输出文字。
而
SetMapMode (hdc, MM_LOENGLISH);
TextOut (hdc, 50, -100, TEXT ("Hello"), 5);
的结果将是 从离客户区左边界 50* 0.01 in .= 0.5 in . 、离上边界 100*0.01 = 1 in . 的位置从左向右输出文字。
但 TextOut 的第 3 个参数为什么是 -100 呢?因为客户区左上角的坐标的默认值始终是 (0,0) 的(后面将详细讲到),而上面的列表不适写了吗 ? 在 MM_LOENGLISH 下, Y 轴值递增的方向是向上,也就是说向下递减,当然此时第 3 个参数为负值了。
Windows 设定这些映射模式是为了让用户使用起来更方便,因此你选定合适的映射模式来简化你的工作;或者选用 MM_ISOTROPIC 、 MM_ANISOTROPIC 自己设定逻辑坐标的单位,数值递增方向;或者干脆就用 MM_TEXT (相当于直接使用设备坐标),需要缩放时用 GetDeviceCap 获得必要的信息后 自己去计算得了。
二、坐标原点
常看到网友问 CDC::SetWindowOrg 和 CDC:: SetViewportOrg 的用法,它们实质是封装了 GDI 函数 SetWindowOrgEx 和 SetViewportOrgEx :
而 CSDN 的解释是:
The SetWindowOrgEx function specifies which window point maps to the viewport origin (0,0). The SetViewportOrgEx function specifies which device point maps to the window origin (0,0).
初学者往往一头雾水。
其实“映射模式”中的“映射”就是数学中的“映射”,一种对应关系或者说是一个数学表达式而已。这个表达式就是:
公式一:
xViewport = (xWindow - xWinOrg) × Kx + xViewOrg
yViewport = (yWindow - yWinOrg) × Ky + yViewOrg
等价公式二:
xWindow = (xViewport - xViewOrg) /Kx + xWinOrg
yWindow = (yViewport - yViewOrg) /Ky + yWinOrg
其中( xWinOrg,yWinOrg ),( xViewOrg,yViewOrg )分别表示逻辑坐标和设备坐标的原点,默认值均为( 0,0 );
( xWindow,yWindow )表示逻辑坐标点,( xViewport,yViewport )表示与之对应的设备坐标点(也就是说,在当前的映射模式下, Windows 将( xWindow,yWindow )影射为( xViewport,yViewport )。);
常数 Kx,Ky 是缩放系数(后面将详细介绍),不同的映射模式下缩放系数不同。
因此,在默认的情况下,( xWinOrg,yWinOrg ) = ( xViewOrg,yViewOrg ) = ( 0,0 ),公式一其实就是:
xViewport = xWindow / Kx yViewport = yWindow / Ky 。
因此,可以看出,映射模式其实就是设定了一个比例而已,没有什么了不起的!
例:
SetMapMode(hdc,MM_TEXT); // 在 MM_TEXT 下缩放比例 K = 1;
SetWindowOrgEx (hdc,100,100,NULL); // 此时( xWinOrg,yWinOrg )被赋值为( 100 , 100 );
// 而 ( xViewOrg,yViewOrg )保持不变为( 0 , 0 )。
那么公式一即为:
xViewport = xWindow -100 yViewport = yWindow -100
因此
TextOut (hdc, 520, 530, TEXT ("ILoveYou,MyGirl"), 15);
// ( xWindow,yWindow ) = ( 520 , 530 )
将会从( 520 , 530 ) - ( 100 , 100 ) = ( 220 , 230 )点开始在设备上显示。
而 SetViewportOrgEx 是用来设定( xViewOrg,yViewOrg )的值的,使用方法与 SetWindowOrgEx 的使用类似。从公式一可以看出,在 MM_TEXT 中,
SetWindowOrgEx (hdc, x, y , NULL) ;
与
SetViewportOrgEx (hdc, - x, - y, NULL);
等价的。
三、缩放系数
缩放系数
Kx = xViewExt / xWinExt
Ky = yViewExt / yWinExt
(xViewExt,yViewExt)和(xWinExt,yWinExt)可分别由 GetViewportExt 和 GetWindowExtEx 得到。
在 MM_TEXT 下, Kx = Ky = 1 ;其它映射模式下Kx、Ky均为常数,它们可以由下表来计算(Window NT,显示设备:1024x768 pixels):
--------------------------------------------------------------------------------------
Mapping Mode Viewport Extents (x, y) Window Extents (x, y)
MM_LOMETRIC (1024, -768) (3200, 2400)
MM_HIMETRIC (1024, -768) (32000, 24000)
MM_LOENGLISH (1024, -768) (1260, 945)
MM_HIENGLISH (1024, -768) (12598, 9449)
MM_TWIPS (1024, -768) (18142, 13606)
------------------------------------------------------------------------------------
表 2 Windows NT Extents (1024 x 768)
参考文献:
MSDN by Microsoft
《 Visual C++ 技术内幕》 by David J. Kruglinski et al
《 Programming Windows 》 5 th Edition ,by Petzoldi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~The End
本人才疏学浅,本文若有什么不当之处,请告知,谢谢。