自本篇文章起,LaoWaiHang将开辟一个《MFC图形函数学习》专栏,与大家共同学习MFC绘制二维图形的有关函数及相关基础知识。希望通过学习过程,与大家共同进步。第一篇文章先介绍MFC绘图的准备工作。
一、MFC编程环境
我这里使用的MFC编程环境的是Visual Studio,版本是2022,使用其它版本也无所谓。这里假定大家已经对MFC有了基本的了解。
二、建立一个MFC单文档项目
步骤:启动VS->创建新项目->选择MFC应用->下一步->确定项目名称(案例中使用:MFC2DGraph,下面提到很多类名、文件名会使用它)、存储位置->创建->应用程序类型:单个文档、项目样式选 MFC标准(其余使用缺省设置)->下一步->文档模板属性:(缺省设置)->用户界面功能:(缺省设置)->高级功能:(缺省设置)->生成的类:(缺省设置)->完成。
说明: a.绘图可以在各种项目中进行,如对话框项目,这里使用单文档项目时为了后续介绍函数使用时表述更为方便。b.关于字符集,使用UNICODE。
三、MFC单文档项目设置好后,我们打开"解决方案管理器",可以看到系统自动生成的若干个头文件、源文件,我们找到源文件MFC2DGraphView.cpp,将其点开往下寻找,可以看到void CMFC2DGraphView::OnDraw(CDC* /*pDC*/),然后我们将括号内pDC前后加的注释去除,也就是让pDC这个指针活起来,这个pDC就是CDC类(设备上下文)指针,绘图函数多需其调用。在这个文件中往下看,可以看到语句"// TODO: 在此处为本机数据添加绘制代码",后边我们学习的所有绘图程序代码都将在这个语句后运行。
四、关于设备坐标系与自定义坐标系
(一)设备坐标系
如果我们不对坐标系进行任何设置,在程序中直接使用绘图函数,这时使用的坐标系就是设备坐标系。它的特点是,以窗口左上角为坐标原点,向右为X轴正方向,向下为Y轴正方向,单位为像素。这种坐标系与我们常用的十字坐标不一致,出现负值时就跑到了屏幕外边。
(二)自定义坐标系
我们自己通过相关函数设置的坐标系称为自定义坐标系。建立一个以窗口中心为原点、X轴正向为水平向右、Y轴正向为垂直向上、有四个象限的十字坐标系,需要使用到下面几个函数:
- 获取窗口客户区数据函数
函数:GetClientRect(rect)
参数:CRect对象,CRect是MFC中一个表示矩形的类,这个类有宽、高等属性
说明:
a.这个函数是CWnd类的成员函数,OnDraw函数所在类是CMFC2DGraphView,其基类是CView,而CView的基类是CWnd;所以我们在OnDraw函数中可以直接使用这个函数(省略this->)。
b.获取的属性值包括窗口显示区域(客户区)宽、高,以及以窗口左上角为坐标原点整个客户区的坐标尺寸位置。
- 映射模式函数
映射的含义是如何将代码中的图形显示在屏幕坐标系中。
函数:SetMapMode(nMapMode)
参数:nMapMode用来指定映射模式(显示方法)
说明:
a.这个函数是设备上下文类的成员函数,使用这个函数需要CDC类对象或指针调用;
b.我们这里要使用的参数取值MM_ANIOSTROPIC(值=8,直接写8也可)。含义:逻辑单位任意,x轴和Y轴的方向和比例可以独立设置;
c. nMapMode还有其它取值,这里不作进一步介绍。
3.设置逻辑窗口尺寸函数
逻辑窗口尺寸可以理解成是我们用户进行代码绘图的坐标系尺寸。
函数:SetWindowExt(width,height)
参数:逻辑窗口的宽、高
说明:
a.这个函数也是设备上下文类的成员函数,使用这个函数需要CDC类指针调用;
b.参数取前面rect对象的值,width=rect.rect.Width(), height=rect.Height(),这样我们可以在整个窗口客户区中进行绘图;
c.我们在程序代码里进行绘图对应的就是逻辑窗口。
4.设置物理窗口尺寸函数
物理窗口可以理解成是设备(显示器)坐标系。
函数:SetViewportExt(width,height)
参数:物理窗口的宽、高
说明:
a.这个函数仍是设备上下文类的成员函数,使用这个函数还是需要CDC类指针调用;
b.参数也是取前面rect对象的值,width=rect.rect.Width(), height=-rect.Height();(注意height加上了负号)
c.可以看到,两个参数取值与逻辑窗口参数大小相同,目的是为了让物理窗口与逻辑窗口1:1映射;在参数height前加了一个负号,是为了将Y轴的正方向调整为向上以符合我们日常习惯。
5.设置自定义坐标系原点函数
函数:SetViewportOrg(x,y)
参数:原点坐标(值为设备坐标系的值)
说明:
a.这个函数也是设备上下文类的成员函数,使用需要CDC类指针调用。
b.把原点放到客户区中心取值:x=rect.Width()/2,y=rect.Height()/2;
6.矩形对象偏移重置函数
函数:OffsetRect(dx,dy)
参数:偏移量
说明:
a.这个函数是CRect对象的成员函数,使用它需要CRect对象调用;
b.原点位置移到客户区中心后,rect左上角坐标如仍为(0,0)的话,rect的左上角跑到了客户区的中心,不能覆盖整个客户区;
c.通过参数取值:x=-rect.Width() / 2, y=-rect.Height() / 2,这样rect的左上角又回到了客户区的左上角。
四、下面把设置自定义坐标系的代码及注释附上(建议收藏,使用时直接复制粘贴到OnDraw函数中即可)
cpp
CRect rect;//定义CRect类对象,这里如果不是取名rect,后边也要相应更改
GetClientRect(rect);//将窗口客户区位置、大小信息保存到rect中
pDC->SetMapMode(MM_ANISOTROPIC); //模式选择:自定义坐标系
//这里的pDC来自于OnDraw函数的参数传入(不一定非起名pDC,如把声明处改了,后续也可跟着改成自己喜欢的名字)
//也可以使用自己声明的设备上下文指针并用函数GetDC()获得当前设备上下文指针
pDC->SetWindowExt(rect.Width(), rect.Height()); //设置逻辑窗口尺寸
pDC->SetViewportExt(rect.Width(), -rect.Height()); //设置窗口物理尺寸
pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);//设置原点
rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//重置rect的位置
上面这段代码,是相对固定的格式,如把它粘贴到OnDraw函数"//TODP:"下面,进行绘图就是在自定义坐标系中绘图;如把它删除或临时注释掉,就回到设备坐标系了。在后边学习的案例中,如提到在自定义坐标系绘制什么图形,就表示有这段代码;如讲在设备坐标系中绘图,就表示没有这段代码。
以上是学习MFC绘图函数的准备工作,下一篇文章开始学习MFC二维绘图函数。