也浅谈Win API函数SetWindowOrgEx与SetViewportOrgEx
在阅读学习Charles Petzold大牛名作《Programming Windows,5th Edition》过程中,对于第5章中讲解的SetWindowOrgEx与SetViewportOrgEx一直不明不白,文中所说的坐标系的移动之类更是弄得我一头雾水。阅读完该章节后,想想似乎只是明白了一点,再想想似乎只是更加糊涂一点。
在MM_TEXT映射模式下,假设cxClient和cyClient分别为客户区x轴和y轴的长度。
使用以下参数调用SetViewportOrgEx函数SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;则调用函数后,logical point(0,0)将映射到device point(cxClient/2, cyClient/2)。原来坐标系统系统(图一)将变为新的坐标系统(图二)。对于这点想想似乎明白。
图一 图二
使用以下参数调用SetWindowOrgEx (hdc, -cxClient / 2, -cyClient / 2, NULL) ;则调用函数后,所得结果同上述调用SetViewportOrgEx 函数。坐标系的变换同图一坐标系统到图二坐标系统的变化。对于这点想想似乎糊涂。
引用《Programming Windows,5th Edition》书中第5章的一段
If you change the viewport origin to (xViewOrg, yViewOrg), the logical point (0, 0) will be mapped to the device point (xViewOrg, yViewOrg). If you change the window origin to (xWinOrg, yWinOrg), the logical point (xWinOrg, yWinOrg) will be mapped to the device point (0, 0), which is the upper left corner. Regardless of any changes you make to the window and viewport origins, the device point (0, 0) is always the upper left corner of the client area.
这段话描述的是这两个函数的作用,读起来一知半解,或许个人的理解能力有待进一步提高吧。不理解,于是求助谷歌。原来不理解这两个函数的人不只是我一个人,很多人都已经讨论过,在博客上,在论坛上。浏览开始的一些讨论文章,情况还停留在即解却尚未解的状态。直到最后阅读了以下的一篇文章《SetViewportOrgEx与SetWindowOrgEx》,然后再在骑车回家的路上一想,恍然大悟,原来是可以这样简单的理解。
在《Programming Windows,5th Edition》书中第5章的The Viewport and the Window一节,讲解了何谓Viewport,何谓Window。因为没有自己的理解顿悟,接下来的SetViewportOrgEx和SetWindowOrgEx函数的迷惑也就理所当然。参考了“包子的小窝~~结庐在人境”的文章后,下面说下自己对于Viewport和 Window的理解:Viewport与屏幕设备相关,或者说同程序的客户区大小相关。在一应用程序当中,不管你调整程序的大小如何,你没有拖动滚动条所能完整看到的客户区内容的大小即是Viewport的大小。
Window与客户区内包含界面大小相关。在一应用程序当中,把滚动条从最左边拖动到最右边,从最上面个拖动到最下面,在这期间你所看到的客户区内全部内容的大小即是Window的大小。它们的关系就如同你从一扇可以平行移动的窗户观看外面的美丽风景。Viewport即是在这扇平行移动窗户静止时,你从这个窗口看出去所能看到的大小(类似滚动条静止你所看到整个客户区)。Window即是在这扇平行移动窗户从可以移动的初始位置移动到最终位置期间你所看到的大小(类似滚动条从左到右从上到下你所看到的内同)。
如果对于Viewport和Window这两个术语有了理解,理解SetViewPortOrgEx和SetWindowOrgEx函数也就顺理成章了。
不管是SetViewportOrgEx函数,还是SetWindowOrgEx函数,调用后的结果都是移动上面Viewport和Window所表示区域原点的相对位置。在MM_TEXT映射模式下,没有调用这两个函数前,Windows操作系统应用程序客户区所表示的Viewport和Window的原点(0,0)均位于客户区最左最顶一角。若调用SetViewportOrgEx函数,则移动Viewport所表示区域坐标系相对Window所表示区域坐标系统相应参数个长度距离。若调用SetWindowOrgEx函数,则移动Window所表示区域坐标系相对Viewport所表示区域坐标系统相应参数个长度距离。不知道大家是否回忆起小时候数学学习的坐标系统移动的经历。若使用正值作为参数移动某个坐标系统,则这个坐标系统相对另外的坐标系统将左移上移某个单位距离;若使用负值作为参数移动某个坐标系统,则这个坐标系统相对另外的坐标系统将右移下移某个单位距离。不管坐标系怎样移动,Window所对应的逻辑坐标系的原点都是固定不变,即你用相应的输出函数在相应的逻辑坐标系上输出的内容仍然是在原来的地方,只是相对于Viewport坐标系的移动,你所能看到的内容有所不同。
以下是根据我的理解调用相应函数的截图。
本程序在客户区输出左上角和右下角分别输出两个圆形(Viewport区域和Window区域一样大小),没调用SetViewportOrgEx函数和SetViewportOrgEx函数,截图如图三。
图三
调用SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);即是Viewport区域左移上移相应参数长度,于是看到将是原先左上角的圆形将在右下角出现,截图如图四。
图四
调用SetWindowOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);即是Window区域左移上移相应参数长度,于是看到的将是原右下角的圆形将在左上角出现,截图如图五
图五
(全文完)