理解 Windows 坐标系
.设备坐标和逻辑坐标
设备坐标( Device Coordinate )又称为物理坐标( Physical Coordinate ),是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的 X 轴向右为正, Y 轴向下为正,坐标原点位于窗口的左上角。
屏幕上有三种不同的物理坐标,每种物理坐标是固定死的,原点, XY 轴方向都不变
1 、客户区域坐标,包括应用程序的客户区域,客户区域的左上角为( 0,   0 )。
2 、屏幕坐标,包括整个屏幕,屏幕的左上角为( 0,   0 )。
用函数 ClientToScreen ScreenToClient 可以将客户区域坐标转换成屏幕区域坐标,或反之。
3 、全窗口坐标,包括一个程序的整个窗口,包括标题条、菜单、滚动条和窗口框,窗口的左上角为( 0,0 )。
逻辑坐标( Logical Coordinate )是系统用作记录的坐标 是以 逻辑单位 为单位来表示的。在缺省的模式( MM_TEXT )下,逻辑坐标的方向和单位与设备坐标的方向和单位相同,也是以像素为单位来表示的, X 轴向右为正, Y 轴向下为正,坐标原点位于窗口的左上角。
逻辑坐标有多种映射模式,可以改变坐标方向和每个逻辑单位的大小
画图在逻辑坐标中画,使用逻辑单位,显示图形在物理坐标中显示。
. 窗口和视口
视口:以像素 ( 即设备坐标 ) 为坐标单位,即用户在屏幕上所观察到的应用程序客户区的一块屏幕区域
窗口:应用程序中的坐标范围,对应逻辑坐标,如 1km ×2km ,在显示时, Windows 需要将窗口坐标 ( 逻辑坐标 ) 映射到视口坐标中 ( 即设备坐标 )
这里说的窗口应该是概念上的世界窗口 , 比如你要显示的图象是 2000*3000 像素,则这个窗口就是 2000*3000 像素。而视口是定义在屏幕窗口上的一块区域,比如定义为 200*300 像素的屏幕窗口区域,且与世界窗口的映射是 1:1, 则视口不能完全显示世界窗口的内容,需要滚动。一般视口是定义为屏幕窗口显示区域的大小。
        考察窗口和视口主要考察它们的原点坐标的设置( SetViewportOrg SetWindowOrg )和坐标单位映射关系( SetViewportExt SetWindowExt )。
. SetViewportOrg SetWindowOrg
1.SetWindowOrg  是把设备坐标的原点移动到逻辑坐标的 (X, Y) 处。
2.SetViewportOrg  是把逻辑坐标的原点移动到设备坐标的 (X, Y) 处。
参见 Sample0.
.   SetWindowExt SetViewportExt
SetWindowExe 设定窗口尺寸, SetViewportExt 设定视口尺寸,窗口尺寸以逻辑单位计算,视口尺寸以物理单位计算。
调用 SetMapMode(MM_ANISOTROPIC) 时,逻辑描画领域坐标系的原点与画面的左上角是重叠的。然后需要调用 SetWindowExt() 函数和 SetViewportExt() 函数,来设定纵轴横轴的単位和方向以及伸缩比例。
virtual CSize SetWindowExt(int cxWindow, int cyWindow);
virtual CSize SetViewportExt(int cxViewport, int cyViewport);
一般说 SetWindowExt() 函数和 SetViewportExt() 函数要成对调用。它们的意思(功能)是:用 cxViewport 个物理像素来表现 cxWindow 个逻辑点(数学上的长度)。同样用 cyViewport 个物理像素来表现 cyWindow 个逻辑点(数学上的长度)。 cx cy 看起来好像是为了设定描画范围参数,其实不然。很简单,它们是代表逻辑长度与物理长度的比值的分子和分母。正负符号也可以设定。当 cxViewport/cxWindow 为正的情况下, X 轴的方向是指向右方,反过来指向左方。  cyViewport/cyWindow 为正的情况下, Y 轴的方向是指向上方,反过来指向下方。
参见 Sample1.
. SetMapMode
该函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位转换为设备单位的度量单位,并定义了设备的 X Y 轴的方向。
Windows 定义了 8 种映射方式,它们在 WINGDI.H 中相应的识别字和含义如表 5-5 所示。
映射方式
逻辑单位
x ( 增加 )
y ( 增加 )
MM_TEXT
图素
MM_LOMETRIC
0.1mm
MM_HIMETRIC
0.01mm
MM_LOENGLISH
0.01in
MM_HIENGLISH
0.001in
MM_TWIPS
1/1440in
MM_ISOTROPIC
任意 (x=y)
可选
可选
MM_ANISOTROPIC
任意 (x!=y)
可选
可选
参见 Sample2.
. 综合运用 1 (加入滚动条)
        滚动条的作用:用来帮助尺寸有限的屏幕窗口显示区域察看无限大的逻辑空间中的内容。逻辑空间是无限大的,屏幕窗口是有限的,利用滚动条可以观察到更多逻辑空间中的内容。
    SCROLLINFO si;
    si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
    si.nMin = 0;
     si.nMax = nHScrollMax ;
    si.nPos = m_nHScrollPos;
    si.nPage = m_nHPageSize;
SetScrollInfo (SB_HORZ, &si, TRUE);
设置垂直方向上可以观察到的逻辑空间内容的范围。
滚动条位置坐标是设备坐标。
参见 Sample3.
 
. 综合运用 2 (加入滚动条及图片缩放)
参见 Sample4.
. 最后总结
  可以认为 CDC 的所有成员函数都以逻辑坐标为参数。
  可以认为 CWnd 的所有成员函数都以设备坐标为参数。
画图并移动图像的步骤:
1. 在脑海中建立逻辑坐标,物理坐标。
2. 确定逻辑坐标的映射模式(即确定轴方向和像素点大小)。
3. CDC 函数开始在逻辑坐标中画图。
4. 使用视口或窗口原点来移动图像到想要的位置。(设置视口或窗口原点)。
问:当滚动条右向拉 10 个单位,逻辑坐标的 (0 0) 到什么地方去了呢?
: 还是 (0,0)
分析 : 滚动条移动是视口移动了 . 变化的是视口的坐标原点,相当于 SetViewportOrg(-10,0) 函数的功能。