映射模式是一种设备环境属性,它会影响GDI绘制。还有其它4种设备环境属性:窗口原点(window origin)、视口原点(viewport origin)、窗口范围(window extents)、视口范围(viewport extents),它们与映射模式密切相关。
几乎所有GDI函数都使用逻辑单位,Windows需要将逻辑单位转换为设备单位(像素),这些转换由映射模式、窗口原点、视口原点、窗口范围、视口范围共同控制。映射模式会决定以什么东西作为逻辑单位,还有x轴/y轴的指向(orientation)。Windows一共定义了8种映射模式,位于wingdi.h文件中。
/* Mapping Modes */ #define MM_TEXT 1 #define MM_LOMETRIC 2 #define MM_HIMETRIC 3 #define MM_LOENGLISH 4 #define MM_HIENGLISH 5 #define MM_TWIPS 6 #define MM_ISOTROPIC 7 #define MM_ANISOTROPIC 8
具体映射模式见下表:
MM_TEXT是最常用的也是最容易理解的,同时也是默认使用的映射模式。在MM_TEXT下,逻辑单位与设备单位相同,都以像素为单位;y轴坐标向下增长,与设备坐标系相同。
GDI提供了两个API,分别用于设置和获取映射模式。MFC的DC类也提供了相应的封装版本。
int SetMapMode( HDC hdc, // handle to device context int fnMapMode // new mapping mode ); int GetMapMode( HDC hdc // handle to device context );
写几行测试代码(MFC):
void CMFCtestDlg::OnPaint() { CPaintDC dc(this); dc.TextOut(100, 100, _T("MM_TEXT:(100, 100)")); dc.SetMapMode(MM_LOMETRIC); dc.TextOut(100, 100, _T("MM_LOMETRIC:(100, 100)")); }
看一下程序的运行效果:
映射模式为默认的MM_TEXT时,输出文本正常,坐标是(100, 100),单位是像素。将映射模式改为MM_LOMETRIC之后,输出的文本没显示出来。这是因为此时y轴的正方向是向上的,原点还是左上角,这样显示位置已经超出可视范围了。将坐标改为(100,
-100):
dc.SetMapMode(MM_LOMETRIC); dc.TextOut(100, -100, _T("MM_LOMETRIC:(100, -100)"));
再看程序的运行效果:
两次的输出文本都正常了。当映射模式为MM_LOMETRIC时,逻辑单位为0.01英寸。
所有的Windows消息(如WM_SIZE、WM_MOVE、WM_MOUSEMOVE)都使用设备坐标(以像素为单位)而不是逻辑坐标,所以映射模式与其无关。
映射模式都会影响哪些GDI函数?映射模式是一种设备环境属性,所以如果一个GDI函数包含DC句柄参数,那映射模式就会影响它。其它GDI函数和非GDI函数,则与映射模式无关。当然,事情也不总是这样。GetDeviceCap是GDI函数,且有一个HDC参数。
int GetDeviceCaps( HDC hdc, // handle to DC int nIndex // index of capability );
经常调用这个函数来获取屏幕的大小,nIndex传递HORZSIZE/VERTSIZE时,获取的是以毫米为单位的物理尺寸。但我们实际使用时,通常是nIndex传递HORZRES/VERTRES,获取以像素为单位的屏幕尺寸。
//If handle is NULL, retrieves the DC for the entire screen. HDC hdcScreen = ::GetDC(NULL); int widthPixels = GetDeviceCaps(hdcScreen, HORZRES); int heightPixels = GetDeviceCaps(hdcScreen, VERTRES); ::ReleaseDC(NULL, hdcScreen);
GetSystemMetrics是非GDI函数,所以它总以设备单位(像素)返回。
int widthPixels = GetSystemMetrics(SM_CXSCREEN); int heightPixels = GetSystemMetrics(SM_CYSCREEN);
GetTextMetrics是GDI函数,并且具有HDC参数,所以它获取的TEXTMETRIC结构中的值是使用逻辑单位的。如果要使用这些值,就要注意输出文本时所使用的映射模式。
学习资料: 《Windows程序设计》