五、GDI映像方式—「度量」映像方式
Windows包含五种以实际尺寸来表示逻辑坐标的映像方式。由于x轴和y轴的逻辑坐标映像为相同的实际单位,这些映像方式能使您画出不变形的圆和矩形。
这五种「度量」映像方式在表5-6中列出,按照从低精度到高精度的顺序排列。右边的两列分别给出了以英寸和毫米为单位时逻辑单位的大小,以便比较。
内定窗口及视端口的原点和范围如下所示:
窗口原点:(0, 0) 可以改变
视埠原点:(0, 0) 可以改变
窗口范围:(1, 1) 不可改变
视埠范围:(1, 1) 不可改变
问号表示窗口和视端口的范围依赖于映像方式和设备的分辨率。前面已经提到过,这些范围本身并不重要,但是表示比例时就必须知道。下面是窗口坐标到视端口坐标的转换公式:
例如,对于MM_LOENGLISH,Windows计算的范围如下:
Windows使用这些来自GetDeviceCaps的有用信息设定范围。只是在Windows 98和Windows NT之间有一点差别。
首先,来看看Windows 98是如何做的:假设您使用「控制台」的「显示」程序选择了96 dpi的系统字体。GetDeviceCaps对于LOGPIXELSX和LOGPIXELSY索引都将传回值96。Windows为视埠范围使用这些值并以表5-7的方式设定视端口和窗口的范围。
这样,对MM_LOENGLISH来说,96除以100的比值是0.01英寸中的图素数。对MM_LOMETRIC来说,96除以254的比值是0.1毫米中的图素数。
Windows NT使用不同的方法设定视端口和窗口的范围(与早期16位版本的Windows一致的方法)。视端口范围依据屏幕的图素尺寸。可以使用HORZRES和VERTRES索引从GetDeviceCaps取得这种信息。窗口范围依据假定的显示大小,它是您使用HORZSIZE和VERTSIZE索引时由GetDeviceCaps传回的。我在前面提到过,这些值一般是320和240毫米。如果您将显示器的图素尺寸设定为1024×768,则表5-8就是Windows NT报告的视端口和窗口范围的值。
这些窗口范围表示包含显示器全部宽度和高度的逻辑单位元数值。320毫米宽的屏幕也为1260 MM_LOENGLISH单位或12.6英寸(320除以25.4毫米/英寸)。
范围中,y前面的负号表示改变了轴的方向。对于这五种映像方式,y值随上升而增加,然而注意内定的窗口和视端口原点均为(0,0)。这个事实有一个有趣的结果。当一开始改变为五种映像方式之一时,坐标系如下:
要想在显示区域显示任何东西,必须使用负的y值。例如下面的程序代码:
将把文字显示在距离显示区域左边和上边各一英寸的地方。
为了使自己保持头脑清醒,您可能想避免这样做。一种解决办法是将逻辑的(0,0)点设为显示区域的左下角,您可以通过呼叫SetViewportOrgEx来完成(假设cyClient是以图素为单位的显示区域的高度):
此时的坐标系如下:
这是直角坐标系的右上象限。
另一种方法是将逻辑(0,0)点设为显示区域的中心:
此时的坐标系如下所示:
现在,我们有了一个真正的4象限笛卡尔坐标系,在x轴和y轴上有相等的按英寸、毫米或twip计算的逻辑单位。
您还可以使用SetWindowOrgEx函数来改变逻辑(0,0)点,但是这稍微困难一些,因为SetWindowOrgEx的参数必须使用逻辑单位,先要将(cxClient,cyClient)用DPtoLP函数转换为逻辑坐标。假设变量pt是型态为POINT的结构,下面的代码将逻辑(0,0)点改变到显示区域的中央:
这五种「度量」映像方式在表5-6中列出,按照从低精度到高精度的顺序排列。右边的两列分别给出了以英寸和毫米为单位时逻辑单位的大小,以便比较。
表5-6 |
映像方式 | 逻辑单位 | 英寸 | 毫米 |
MM_LOENGLISH | 0.01 in. | 0.01 | 0.254 |
MM_LOMETRIC | 0.1 mm. | 0.00394 | 0.1 |
MM_HIENGLISH | 0.001 in. | 0.001 | 0.0254 |
MM_TWIPS | 1/1400 in. | 0.000694 | 0.0176 |
MM_HIMETRIC | 0.01 mm. | 0.000394 | 0.01 |
窗口原点:(0, 0) 可以改变
视埠原点:(0, 0) 可以改变
窗口范围:(1, 1) 不可改变
视埠范围:(1, 1) 不可改变
问号表示窗口和视端口的范围依赖于映像方式和设备的分辨率。前面已经提到过,这些范围本身并不重要,但是表示比例时就必须知道。下面是窗口坐标到视端口坐标的转换公式:
首先,来看看Windows 98是如何做的:假设您使用「控制台」的「显示」程序选择了96 dpi的系统字体。GetDeviceCaps对于LOGPIXELSX和LOGPIXELSY索引都将传回值96。Windows为视埠范围使用这些值并以表5-7的方式设定视端口和窗口的范围。
表5-7 |
映像方式 | 视埠范围(x,y) | 窗口范围(x,y) |
MM_LOMETRIC | (96, 96) | (254, -254) |
MM_HIMETRIC | (96, 96) | (2540, -2540) |
MM_LOENGLISH | (96, 96) | (100, -100) |
MM_HIENGLISH | (96, 96) | (1000, -1000) |
MM_TWIPS | (96, 96) | (1440, -1440) |
Windows NT使用不同的方法设定视端口和窗口的范围(与早期16位版本的Windows一致的方法)。视端口范围依据屏幕的图素尺寸。可以使用HORZRES和VERTRES索引从GetDeviceCaps取得这种信息。窗口范围依据假定的显示大小,它是您使用HORZSIZE和VERTSIZE索引时由GetDeviceCaps传回的。我在前面提到过,这些值一般是320和240毫米。如果您将显示器的图素尺寸设定为1024×768,则表5-8就是Windows NT报告的视端口和窗口范围的值。
表5-8 |
映像方式 | 视埠范围(x,y) | 窗口范围(x,y) |
MM_LOMETRIC | (1024, -768) | (3,200, 2,400) |
MM_HIMETRIC | (1024, -768) | (32,000, 24,000) |
MM_LOENGLISH | (1024, -768) | (1,260, 945) |
MM_HIENGLISH | (1024, -768) | (12,598, 9,449) |
MM_TWIPS | (1024, -768) | (18,142, 13,606) |
范围中,y前面的负号表示改变了轴的方向。对于这五种映像方式,y值随上升而增加,然而注意内定的窗口和视端口原点均为(0,0)。这个事实有一个有趣的结果。当一开始改变为五种映像方式之一时,坐标系如下:
SetMapMode (hdc, MM_LOENGLISH) ; TextOut (hdc, 100, -100, "Hello", 5) ;
为了使自己保持头脑清醒,您可能想避免这样做。一种解决办法是将逻辑的(0,0)点设为显示区域的左下角,您可以通过呼叫SetViewportOrgEx来完成(假设cyClient是以图素为单位的显示区域的高度):
SetViewportOrgEx (hdc, 0, cyClient, NULL) ;
另一种方法是将逻辑(0,0)点设为显示区域的中心:
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;
您还可以使用SetWindowOrgEx函数来改变逻辑(0,0)点,但是这稍微困难一些,因为SetWindowOrgEx的参数必须使用逻辑单位,先要将(cxClient,cyClient)用DPtoLP函数转换为逻辑坐标。假设变量pt是型态为POINT的结构,下面的代码将逻辑(0,0)点改变到显示区域的中央:
pt.x = cxClient ; pt.y = cyClient ; DptoLP (hdc, &pt, 1) ; SetWindowOrgEx (hdc, -pt.x / 2, -pt.y / 2, NULL) ;