1.2.2构造和析构CDC对象

void CMyView::MyFunction()

{.......

CRect rect;

CClientDC dc(this);

dc.GetClipBox(rect);

.............

}

or

void CMyView::MyFunction()

{.......

CRect rect;

CDC* pDC=GetDC();

pDC->GetClipBox(rect);

.......

ReleaseDC(pDC);

}

1.3设备环境中的坐标映射

显示器的逻辑尺寸和物理尺寸

设备坐标,逻辑坐标和物理坐标

映射模式:1.

MM_TEXT映射模式

*************************************************************************************************************

『VC++技术内幕』学习笔记(6)

第六篇:映射模式

  在此篇之前我们已经学会了在窗口显示图形,更准确的说是在窗口指定位置显示图形或文字,我们使用的坐标单位是象素,称之为设备坐标。看下面语句:

pDC->Rectangle(CRect(0,0,200,200));

  画一个高和宽均为200个象素的方块,因为采用的是默认的MM_TEXT映射模式,所以在设备环境不一样时,画的方块大小也不一样,在1024*768的显示器上看到的方块会比640*480的显示器上的小(在不同分辨率下的屏幕象素,在WINDOWS程序设计一书中有示例程序可以获得,或者可以用GetClientRect函数获得客户区的矩形大小。在这里就不说了,大家只要知道就行了),在输出到打印机时也会有类似的情况发生。如何做才能保证在不同设备上得到大小一致的方块或者图形、文字呢?就需要我们进行选择模式映射,来转换设备坐标和逻辑坐标。

Windows提供了以下几种映射模式:

MM_TEXT
MM_LOENGLISH
MM_HIENGLISH
MM_LOMETRIC
MM_HIMETRIC
MM_TWIPS
MM_ISOTROPIC
MM_ANISOTROPIC

下面分别讲讲这几种映射模式:

MM_TEXT:

  默认的映射模式,把设备坐标被映射到象素。x值向右方向递增;y值向下方向递增。坐标原点是屏幕左上角(0,0)。但我们可以通过调用CDC的SetViewprotOrg和SetWindowOrg函数来改变坐标原点的位置看下面两个例子:

//************************************************
// 例子6-1
void CMyView::OnDraw(CDC * pDC)
{
pDC->Rectangle(CRect(0,0,200,200));//全部采用默认画一个宽和高为200象素的方块
}

//**************************************************
// 例子6-2
void CMyView::OnDraw(CDC * pDC)
{
pDC->SetMapMode(MM_TEXT);//设定映射模式为MM_TEXT
pDC->SetWindowOrg(CPoint(100,100));//设定逻辑坐标原点为(100,100)
pDC->Rectangle(CRect(100,100,300,300));//画一个宽和高为200象素的方块
}

  这两个例子显示出来的图形是一样的,都是从屏幕左上角开始的宽和高为200象素的方块,可以看出例子2将逻辑坐标(100,100)映射到了设备坐标(0,0)处,这样做有什么用?滚动窗口使用的就是这种变换。

固定比例映射模式:

MM_LOENGLISH、MM_HIENGLISH、MM_LOMETRIC、MM_HIMETRIC、MM_TWIPS这一组是Windows提供的重要的固定比例映射模式。

它们都是x值向右方向递增,y值向下递减,并且无法改变。它们之间的区别在于比例因子见下:(我想书上P53页肯定是印错了,因为通过程序实验x值向右方向也是递增的)

MM_LOENGLISH 0.01英寸
MM_HIENGLISH 0.001英寸
MM_LOMETRIC 0.1mm
MM_HIMETRIC 0.01mm
MM_TWIPS 1/1440英寸 //应用于打印机,一个twip相当于1/20磅,一磅又相当于1/72英寸。

看例3

//**************************************************
// 例子6-3
void CMyView::OnDraw(CDC * pDC)
{
pDC->SetMapMode(MM_HIMETRIC);//设定映射模式为MM_HIMETRIC
pDC->Rectangle(CRect(0,0,4000,-4000));//画一个宽和高为4厘米的方块
}

  还有一种是可变比例映射模式,MM_ISOTROPIC、MM_ANISOTROPIC。用这种映射模式可以做到当窗口大小发生变化时图形的大小也会相应的发生改变,同样当翻转某个轴的伸展方向时图象也会以另外一个轴为轴心进行翻转,并且我们还可以定义任意的比例因子,怎么样很有用吧。
MM_ISOTROPIC、MM_ANISOTROPIC两种映射模式的区别在于MM_ISOTROPIC模式下无论比例因子如何变化纵横比是1:1而M_ANISOTROPIC模式则可以纵横比独立变化。

让我们看例子4

//**************************************************
// 例子6-4
void CMy002View::OnDraw(CDC* pDC)
{
CRect rectClient; //
GetClientRect(rectClient);//返回客户区矩形的大小
pDC->SetMapMode(MM_ANISOTROPIC);//设定映射模式为MM_ANISOTROPIC
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt (rectClient.right ,-rectClient.bottom );
//用SetWindowExt和SetViewportExt函数设定窗口为1000逻辑单位高和1000逻辑单位宽
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2 );//设定逻辑坐标原点为窗口中心
pDC->Ellipse(CRect(-500,-500,500,500));//画一个撑满窗口的椭圆。
// TODO: add draw code for native data here
}

怎么样,屏幕上有一个能跟随窗口大小改变而改变的椭圆。把 pDC->SetMapMode(MM_ANISOTROPIC);这句改为pDC->SetMapMode(MM_ISOTROPIC)会怎样?大家可以试试。那还有一个问题就是上例的比例因子是多少呢?看下面公式(注意是以例子4为例的)

x比例因子=rectClient.right/1000 //视窗的宽除以窗口范围
y比例因子=-rectClient.bottom/1000 //视窗的高除以窗口范围

  从Windows的鼠标消息可以获得鼠标指针的当前坐标值(point.x和point.y)此坐标值是设备坐标。

很多MFC库函数尤其是CRect的成员函数只能工作在设备坐标下。
还有我们有时需要利用物理坐标,物理坐标的概念就是现实世界的实际尺寸。
设备坐标-逻辑坐标-物理坐标之间如何进行转换便成为我们要考虑的一个问题,物理坐标和逻辑坐标是完全要我们自己来做的,但WINDOWS提供了函数来帮助我们转换逻辑坐标和设备坐标。

CDC的LPtoDP函数可以将逻辑坐标转换成设备坐标
CDC的DPtoLP函数可以将设备坐标转换成逻辑坐标

下面列出我们应该在什么时候使用什么样的坐标系一定要记住:

◎CDC的所有成员函数都以逻辑坐标为参数
◎CWnd的所有成员函数都以设备坐标为参数
◎区域的定义采用设备坐标
◎所有的选中测试操作应考虑使用设备坐标。
◎需要长时间使用的值用逻辑坐标或物理坐标来保存。因设备坐标会因窗口的滚动变化而改变。
用书上的例子作为以前几篇的复习,如果你能够独立完成它说明前面的内容已经掌握。另外有些东西是新的,我会比较详细的做出说明,例如客户区、滚动窗口等。

"可变比例”映射模式

“可变比例”映射模式

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 函数来规格化矩形。

映射模式

又称之为坐标系,在Windows下有几种映射模式,以适应不同的需要。它们分别是: MM_TEXT映射模式,固定比例映射模式,可变比例映射模式。下面我们分别来对以上几种映射模式作详细的说明:

1.MM_TEXT映射模式:
该模式下,坐标被映射到了象素,x值向右方向递增,y值向下方向递增,但我们可以通过调用CDC类中的SetViewportOrg和SetWindowOrg函数来改变坐标原点的位置.

2.固定比例映射模式:
该模式下,坐标系的单位固定的长度,x值向右方向递减,y值向下方向递减(这与MM_TEXT映射模式恰好相反).对于固定比例映射模式中,由于比例因子,也就是逻辑单位的不同,也分为5种不同的映射模式: MM_LOENGLISH(0.01inch)   MM_HIENGLISH(0.001inch) MM_LOMETRIC(0.1mm)   MM_HIMETRIC(0.01mm)   MM_TWIPS(1/1440inch,该模式一般用于打印机).

3.可变比例映射模式:
Windows提供的两种映射模式MM_ISOTROPIC和MM_ANISOTROPIC,允许我们改变它们的比例因子和坐标原点.两种映射模式的不同在于,MM_ISOTROPIC映射模式下,xy单位比例始终是1:1; 而在MM_ANISOTROPIC映射模式下,xy比例因子是可以独立变化的。
CDC类中的一些函数:
SetWindowExt函数:设定窗口的大小
SetWindowOrg函数:设定窗口坐标原点
SetMapMode函数:设定映射模式;
SetViewportExt函数:设定视窗坐标范围(该视窗可见)
SetViewportOrg函数:设定视窗坐标原点位置。
对于VC 中的映射模式值得我们注意的几点是:
1。从上面的叙述中,我们可以这样理解Windows坐标系,它包含两层,第一层为物理坐标系,第二层为逻辑坐标系。根据不同的应用场合我们使用不同的坐标系。
2。CDC类同样也给了我们两个坐标系转换的函数,LPtoDP和DPtoLP,完成从逻辑到设备和从设备到逻辑的转换。
3。对OnLButtonDown(CPoint point,nFlag)函数中的point参数,所获得的鼠标位置为设备坐标。

转载于:https://blog.51cto.com/wkm120/481784

vc++图形编程基础相关推荐

  1. c语言编程基础课件,第7章_C语言图形编程基础课件

    第7章_C语言图形编程基础课件 狭义的组织变革是指组织根据外部环境的变化和内部情况的变化及时地改变自己的内在组织结构,以适应客观发展的需要. 狭义的组织变革是指组织根据外部环境的变化和内部情况的变化及 ...

  2. VC++游戏编程基础无法找到“d3d9.h”问题

    经反复查阅是缺少Direct X SDK导致的,我用的是VC++6.0,支持Direct X SDK 9.0b及之前的版本,最新版DX SDK(JUNE)VC6驾驭不了...下面是我解决问题的思路(只 ...

  3. 计算机图形编程基础,Windows图形编程基础.ppt

    Windows图形编程基础 软件教研室 计算机图形学 第三章 Window图形编程基础 一.设备描述表DC及相关的MFC类 二.图形设备接口(GDI : Graphics device Interfa ...

  4. windows图形编程基础

    windows图形编程基础 2010年08月30日 图形设备接口(GDI,Graphics Device Interface)的主要目标之一是支持在输出设备(如视频显示器.打印机和绘图仪)上的与设备无 ...

  5. 【一篇文章带你读完《C++游戏与图形编程基础 第2版》】

    <C++游戏与图形编程基础 第2版> 下载地址:https://download.csdn.net/download/qq_23996157/10745496 AGK(App Game K ...

  6. python图形编程基础-Python从基础到入门系列教程

    本教程集合了Python基础&系统管理,从基础到入门,带你走进Python世界!对Python有兴趣的可以学习一下哦基础系列:1.课程简介2.Python下载和安装3.IDLE使用简介4.第1 ...

  7. python图形编程基础知识_AI-图像基础知识-01|python基础教程|python入门|python教程

    目前人工智能Artificial Intelligence主要分为两大分支: 计算机视常见:Computer Vision,简称CV CV主要是研究如何让机器看懂世界的一种技术,通过各种光学传感器来代 ...

  8. python图形编程基础知识_少儿Python基础(14) | 图形用户界面编程(1)–easygui

    可爱的小朋友们,相信小朋友对哪些带有按钮,文本,输入框这些窗口的都不陌生了,这就是图形用户编程. 目前有很多Python的GUI工具包可以选择,那今天我们来学习GUI的一个很简单的工具包easygui ...

  9. qprocess回调_Qt图形编程基础之:Qt/Embedded开发入门-嵌入式系统-与非网

    12.2.1  Qt/Embedded介绍 1.架构 Qt/Embedded以原始Qt为基础,并做了许多出色的调整以适用于嵌入式环境.Qt/Embedded通过Qt API与Linux I/O设施直接 ...

最新文章

  1. ORACLE用户权限管理笔记整理
  2. 刷题向》关于一道比较优秀的递推型DP(openjudge9275)(EASY+)
  3. 如何快速清理docker资源
  4. layui分页limit不显示_【图片】新手 分页显示不了呀【layui吧】_百度贴吧
  5. leetcode - 1201. 丑数 III
  6. leetcode题解677-键值映射
  7. Python+Selenium练习篇之4-利用link text定位元素
  8. cf319.B. Modulo Sum(dp 鸽巢原理 同余模)
  9. SpringBoot+zk+dubbo架构实践(四):sb+zk+dubbo框架搭建(内附源码GitHub地址)
  10. STM32 SIM800C SIM868 连接OneNet 以及远程控制流程详解
  11. HAL库的学习 ——FLASH的使用
  12. abp The value could not be converted to a GUID:
  13. Ant笔记(一)Ant下载与安装
  14. 程序员光学技术还不够?推荐一份运营书单给你品一品
  15. python爬虫教程:实例讲解Python爬取网页数据
  16. 诺兰回归,方舟渡劫——短信登录京东青龙
  17. MIT Mini Cheetah仿真环境搭建(VMware中的ubuntu20.04,含问题解决)
  18. MyBatis源码简单分析
  19. 程序员笔试面试注意事项-1
  20. Android 实现微信语音聊天

热门文章

  1. 丢弃Git中的本地提交
  2. 项目启动后去除项目标题,去除时间与状态栏Android
  3. MTK:MVRAM操作
  4. C语言随笔小算法:char字节流与结构体变量相互转换
  5. java 反射 方法 修饰符_超类中使用默认修饰符的Java反射访问方法
  6. 天梯—奇偶分家(C语言)
  7. Open3d之计算源点云与目标云的距离
  8. ubuntu之安装sublime text
  9. Eigen教程(2)之Matrix,Vectors, Dynamic介绍
  10. springboot testcontext @sql_SpringBoot图文教程11—从此不写mapper文件「集成MybatisPlus」...