一、设备坐标系
Windows会把GDI函数中指定的逻辑坐标转换为设备坐标。Windows中有三种设备坐标系。所有的设备坐标系都以像素为单位,x轴向右增加,y轴向下增加。
(1)屏幕(screen)坐标系
原点(0,0)在屏幕左上角。WM_MOVE(对于非子窗口)消息,一些Windows函数:CreateWindow、MoveWindow(对于非子窗口)、GetMessagePos、GetCursorPos、SetCursorPos、GetWindowRect、WindowFromPoint等等使用屏幕坐标系。
如何获取屏幕DC?可以这样:
HDC hdcScreen = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); //or HDC hdcScreen = ::GetDC(NULL);
当使用屏幕DC时,在GDI调用中,逻辑坐标值将被默认映射到屏幕坐标。
(2)全窗口坐标系
用于一个应用程序的整个窗口,包括标题栏、菜单、滚动条、边框。原点(0,0)在整个窗口的左上角。获取全窗口DC:
//Retrieves the device context (DC) for the entire window. HDC hdcEntireWindow = ::GetWindowDC(GetSafeHwnd());
全窗口坐标系一般用的比较少,也就是想在标题栏上画点什么东西时会用到它。
(3)客户区坐标系
最常用的设备坐标系,仅包含客户区,不包括标题栏、菜单、滚动条、边框等等,原点(0,0)在客户区的左上角。获取客户区DC:
PAINTSTRUCT ps; //Should only call BeginPaint in response to a WM_PAINT message. HDC hdcClient = ::BeginPaint(GetSafeHwnd(), &ps); //or HDC hdcClient = ::GetDC(GetSafeHwnd()); //or (MFC) CClientDC dcClient(this);
关于BeginPaint与GetDC的区别,可以参考:MFC
Windows程序设计总结(一)—— BeginPaint/EndPaint与GetDC/ReleaseDC。
可以使用ClientToScreen/ScreenToClient函数将设备坐标在客户区坐标系和屏幕坐标系之间相互转换。
BOOL ClientToScreen( HWND hWnd, LPPOINT lpPoint ); BOOL ScreenToClient( HWND hWnd, LPPOINT lpPoint );
GetWindowRect函数获取使用屏幕坐标系的窗口位置和大小。
二、视口(viewport)与窗口(window)
映射模式定义了窗口(Window)(逻辑坐标)到视口(viewport)(设备坐标)的映射,而设备坐标系又取决于所使用的DC(见第一部分)。视口使用设备坐标(单位是像素),而窗口使用逻辑坐标(单位可能是像素、毫米、英寸等)。
可以使用如下公式将窗口的逻辑坐标转换为视口的设备坐标:
其中,(xWindow,yWindow)是待转换的逻辑坐标,(xViewPort,yViewPort)是转换后的设备坐标。(xWinOrg,yWinOrg)是(逻辑坐标系下)的窗口原点,(xViewOrg,yViewOrg)是(设备坐标系下)的视口原点。(xWinExt,yWinExt)是(逻辑坐标系下)的窗口范围,(xViewExt,yViewExt)是(设备坐标系下)的视口范围。窗口原点一定映射到视口原点,然后坐标按视口范围和窗口范围的比例进行转换。
例如,当映射模式为MM_LOENGLISH时,逻辑坐标是按照每百分之一英寸(逻辑单位)的像素数(设备单位)的比例来进行转换的。为了提高性能,所有值使用整数,不使用浮点数。
默认情况下窗口原点和视口原点的坐标都是(0,0),这时公式可以简化为:
另外范围也可能是负值,这取决于x轴/y轴的指向。
也可以使用如下公式将视口的设备坐标转换为窗口的逻辑坐标:
有两个API函数可以完成逻辑坐标点和设备坐标点之间的转换。
BOOL LPtoDP( HDC hdc, LPPOINT lpPoints, int nCount ); BOOL DPtoLP( HDC hdc, LPPOINT lpPoints, int nCount );
例如,将GetClientRect返回的设备坐标的客户区尺寸转换为逻辑坐标:
RECT rcClient = { 0 }; ::GetClientRect(GetSafeHwnd(), &rcClient); DPtoLP(hdcClient, (LPPOINT)&rcClient, 2);
转换完之后,发现没有任何改变,这是因为在默认的映射模式MM_TEXT下,逻辑坐标和设备坐标一样,也是以像素为单位,并且原点都是(0,0)。
学习资料: 《Windows程序设计》