现在的位置: 首页 > 综合 > 正文

GDI编程总结(二)—— GDI映射模式【续】

2014年09月02日 ⁄ 综合 ⁄ 共 2012字 ⁄ 字号 评论关闭
文章目录

一、设备坐标系

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);

关于BeginPaintGetDC的区别,可以参考: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程序设计》

抱歉!评论已关闭.