“可变比例”映射模式
Windows提供了两种映射模式MM_ISOTROPIC 和 MM_ANISOTROPIC,允许自由改变它们的比例因子、坐标原
点、X轴和Y轴的正方向。
在MM_ISOTROPIC 映射模式下,纵横比总是 1:1 ,无论比例因子如何变化,圆总是圆;
在MM_ANISOTROPIC 映射模式下,X 和 Y 的比例因子可以独立地变化,就是说用它们各自的一个逻辑单位换算
成现实世界中的物理单位大小(如 像素,英寸,厘米,毫米),得到的结果可能是不同的;所以,圆可以被拉扁成椭圆。
例1:
void CTestView::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(&rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt(rectClient.right, -rectClient.bottom);
pDC->SetViewportOrg(rectClient.right / 2, rectClient.bottom / 2); pDC->Ellipse(CRect(-500, -500, 500, 500));
}SetWindowExt(1000,1000); // 设置窗口大小为 1000个逻辑单位宽,1000个逻辑单位高
SetViewportExt(rectClient.right, -rectClient.bottom); // 设置窗口大小为 right 像素宽,bottom像素高
SetViewportOrg(rectClient.right/2, rectClient.bottom/2); // 将坐标原点设在窗口中心
可以看出窗口的大小使用了两种单位来表示,一种是逻辑单位,一种是设备单位(这里是像素)。
X轴上 1000 个逻辑单位 = right 像素,既 1个逻辑单位 = right / 1000 像素;这就是所谓的比例因子了,这里
X比例因子 = right / 1000
Y比例因子 = bottom / 1000
( 注:本例中right、bottom是变量,就是窗口的实际大小,是随着用户的调整动态改变的;当然也可以把它设成固
定的数值,不过如果是这样,图形的大小不会随着窗口大小的变化而变化,总是固的大小。)
无论窗口的实际大小如何改变,X轴上 1000个逻辑单位总是等于窗口的宽, Y轴上1000个逻辑单位总是等于窗口
的高这就是为什么上例中椭圆总是能撑满窗口的原因。
SetViewportExt函数中,两个参数的正负决定了X,Y轴的正方向;如上例中X轴右递增,Y轴下递减。
上例画出的图形:
如果试着把参数 -rectClient.bottom 改成正的 rectClient.bottom ,这样就变成 X轴右递增,Y轴下递增。
再运行程序发现所画出的图形和上图是一样的。 这是因为在这两种情况下 CRect(-500, -500, 500, 500) 里的一对
坐标值 (-500, -500) (500, 500) 恰好表示了矩形中不同对角线上的两个点。原例子中(-500, -500) 位于左下角而
(500, 500) 位于右上角; 第二种情况下,(-500, -500) 位于左上角而 (500, 500) 位于右下角。
例2:
void CTestView::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(&rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt(rectClient.right, -rectClient.bottom); pDC->Ellipse(CRect(-500, -500, 500, 500));
}
在这个例子中我们把设置窗口原点的这一句去掉了 SetViewportOrg(rectClient.right/2, rectClient.bottom/2);
现在画出的图形变成了:
我们看到图形只画出了 1/4 ,这是因为现在的坐标原点位于窗口的左上角了。现在X和Y轴上的两个坐标值
(-500, -500)、(500, 500) 与原先相比表达了不同的含义,因为整个坐标系已经移位。
我们把最后一个函数改成:
pDC->Ellipse(CRect(0, 0, 1000, -1000)); // (0,0) 左上角; (1000,-1000) 右下角
编译运行,发现画出的图形与例1是样的。
现在继续修改代码,让Y 坐标轴下递增:
void CTestView::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(&rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt(rectClient.right, rectClient.bottom); // 第二个参数由负改成正 pDC->Ellipse(CRect(0, 0, 1000, 1000));
}
再次编译运行,发现还是一模一样!
另外,其中一句代码改成 pDC->SetViewportExt(rectClient.Width(), rectClient.Height()); 也是可以的。
From MSDN:
RECT 结构:
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
RECT 结构定义了一个矩形的左上角坐标和右下角坐标
成员变量:
left
矩形左上角的X坐标
top
矩形左上角的Y坐标
right
矩形右下角的X坐标
bottom
矩形右下角的Y坐标
class CRect : public tagRECT
{
public:// Constructors
...
// Attributes (in addition to RECT members)
int Width() const; // retrieves the width
int Height() const; // returns the height
CSize Size() const; // returns the size
...
};CRect::Width
int Width( ) const;
返回值:
矩形CRect的宽度
描述:
通过计算 right - left 得到矩形CRect的宽度;结果可能为负值。
注意:
矩形必须是经过规格化的,不然此函数可能会失败。你可以在调用此函数之前先调用 NormalizeRect 函数来规格化矩形。
CRect::Height
int Height( ) const;
返回值:
矩形CRect的高度
描述:
通过计算 bottom - top 得到矩形CRect的高度;结果可能为负值。
注意:
矩形必须是经过规格化的,不然此函数可能会失败。你可以在调用此函数之前先调用 NormalizeRect 函数来规格化矩形。