计算机图形学实验一 《MFC绘图基础》
视频讲解:无没啥讲的,有一些东西在实验二视频提了一下
一.MFC介绍
1.基本介绍:
MFC是微软公司提供的一个类库,以C++类的形式封装了Windows API,并且包含一个应用程序框架。
说人话就是一个框架里面自带很多工具,减少了很多你编码得时间提高效率。
因为自带一个框架所以在你创建MFC应用的时候就可以运行。
关于各分区域的介绍他都有中文写着的也不需要了解太多,需要知道的就是中间那个白色矩形框叫客户区,我们一般绘制图形都是在这个区域上绘制的。
接下来介绍一下MFC工程信息
主要就是右边解决方案视图如果你没有这个你点一下最上面那个视图的第一个解决方案资源管理器就有了。这个视图主要就是看头文件和源文件,C++的类就是由源文件和头文件组成得。
头文件:一般类的声明(包括类成员和方法的声明),函数原型,#define(宏定义)等,一般不写具体实现。
源文件:主要写实现头文件已经声明的那些函数的具体代码,需要注意的是,在文件开头必须#include实现的头文件,不过这个框架基本都是声明好的如果你新写了一个类,然后在源文件去实现对应的头文件函数那就得#include声明
主要就是介绍一下TestView类(这个Test取决于你这个工程叫啥你叫aaa那就是aaaView),这个类就是将文档中的数据可视化,我们绘制图像就是通过这个类来实现的。
2.OnDraw(CDC* pDC)函数
在MFC中我们绘制图形就是在TestViwe类中的OnDraw函数中实现的。他专业有中文注释一看就知道就在那个TODO注释下面写代码就行,如果你想深入了解OnDraw函数可以去看他的官方文档
你用鼠标点一下你想查的然后再点一下练级搜索去看他的官方文档就行了或者一些大佬写的博客也行,这里我只是简单介绍一下。
首先刚刚说了TestView类就是将文档中的数据可视化,而绘制就是通过Ondraw来实现的所以代码前几行自带的意思就是把CDC指针指向文档然后判断指针是否正确指向了,然后那个CDC指针一开始是注释掉的因为在你创建这个工程的时候并没有绘制任何东西所以把他注释掉是为了不报warning,不注释掉他可能就会说你没用占着* * 不拉*,不过接下来我们要绘制图像肯定是要用他的所以要把它释放出来就是把注释解除。
3.CDC:
这里简单介绍一下CDC类,同样想深入了解的可以百度去查,这里简单介绍一下,首先他的翻译就很垃圾很误人子弟,CDC类定义的是设备上下文对象的类,这是官方说的因为DC英文是(Device Context)直译过来就是设备上下文,但是这个翻译很让人难理解更准确的来说他应该叫设备环境,设备场景等。
关于设备环境他就是就是是一个Windows数据结构,或者也有人说是一个结构体,是一个类等等都可以,它包含了某个设备的绘制属性。通常,绘制调用都是借助于上下文对象,而这些设备上下文对象封装了用于画线、形状、文本等的Windows API。
说人话就是,假如你正在画画,那设备环境就是那张画布,加上很多工具比如画笔,画刷,颜料等等,接下来请记住一点Widnows下的所有绘图都是通过设备场景进行的。
4.常见设备上下文及区别:CClientDC,CPaintDC,CWindowDC
CClientDC:(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,
析构函数中包含了ReleaseDC。只能在客户区绘制图形。
CPaintDC:只能在客户区绘制图形。(1)CPaintDC类是CDC类的一个派生类,该类一般用在响应WM_PAINT消息的函数OnPaint()中。(2)WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息。当程序中的消息循环接到WM_PAINT消息时就自动调用消息处理函数OnPaint(),如果在OnPaint函数内定义了CPaintDC类的对象,通过这个类对象就可以使用CDC类的成员函数完成视图客户区中的图形绘制操作。(3)CPaintDC用于响应窗口重绘消息(WM_PAINT)时的绘图输出。CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在WM_PAINT消息处理之中。
CWindowsDC:(1)可在非客户区绘制图形,而CClientDC,CPaintDC只能在窗口的客户区绘制图形。(2)坐标原点是在窗口的左上角,CClientDC,CPaintDC的坐标原点是在客户区的左上角。
5.获取设备上下文的方法:
1、通过OnDraw()函数获得CPaintDC:在OnDraw()函数中入口参数CDC *pDC,传入这即操作的设备上下文,这个上下文既是CPaintDC。他是通过OnPaint()构建,并传入OnDraw(),View类如果没有重载OnPaint(),则窗口刷新时自动调用MFC底层代码的OnPaint()函数,从而调用OnDraw()。我们就可以通过OnDraw()在客户区进行初始化的绘制。
2、通过CClientDC,CPaintDC,CWindowDC定义一个DC。
例如:CClientDC dc(this);创建一个dc,在当前对象的客户区。创建一个CWindowDC类的对象:CWindowDC dc(this);
二.MFC基本绘图函数和类介绍
常见类:
- CPoint类:存放点坐标(x,y);
- CRect类:存放矩形左上顶点和右下角顶点的坐标(top、left、right、bottom),其中(top,left)为矩形的左上角点,(right,bottom)为矩形的右下角点;
- CSzie类:存放矩形的宽度和高度的坐标(cx,cy),其中cx为矩形的宽度,cy为矩形的高度。
- CBitmap:封装了一个GDI位图,提供位图操作的接口;
- CFont:封装了GDI字体,可以选作设备上下文中的当前字体;
- CBrush:封装了GDI画刷,选作设备上下文的当前画刷,画刷用于填充图形内部;
- CPen:封装了GDI画笔,选作设备上下文的当前画笔,画笔用于绘制图形边界线;
- CPallette:封装了GDI调色板,提供应用程序和显示器之间的颜色接口;
- CGdiObject:GDI绘图工具的基类,一般不能直接使用。
常用函数:
函数名 | 作用 |
---|---|
CreatePen | 创建画笔,属性:线性(比如实线虚线等),宽度,颜色、 |
CreateSolidBrush | 创建画刷,填充封闭图形 |
SetPixel | 绘制像素点,返回画的那个点的RGB值(0,255) |
SetPixelV | 同上但是返回的是true和false,所以比上面那个快一般都用这个 |
MoveTo | 参数是一个点的x,y坐标,表示移动到当前位置。 |
LineTo | 参数同上,绘制直线段 |
Rectangle | 绘制矩形 |
Ellipse | 绘制椭圆 |
FillSolidRect | 填充矩形颜色 |
其他函数可以自己摸索着试试你用的时候看看原型参数是啥画一画,所见即所学的东西就不赘述了。
不过要说的是设备默认坐标系是原点在左上角,x向右为正方形,y向下为正方向,但这样其实是反逻辑的,所以接下来介绍如何自定义二维坐标系
二.自定义二维坐标系
为什么要自定义二维坐标系呢,简单地说比如你画个圆如果实在默认设备坐标系下的话只能画出1/4圆
大概就是这样,所以为了能更好的展示我们绘制的图像自定义坐标系,通常就是这样
就是原点在中心,x向右为正方形,y向上为正方向
1.设置映射函数
使用映射模式函数,设置窗口大小和视区大小相等自定义二维坐标系,
映射模式很多就说一个最常用的
模式代码 | 宏定义值 | 坐标系特征 |
---|---|---|
MM_ANISOTROPIC | 8 | 逻辑单位被转换为任意单位,x轴和y轴的方向和比例独立设置 |
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();//指针指向文档(document)把文档把文档以视图形式展现
ASSERT_VALID(pDoc);//判定指针是否为空
if (!pDoc)//为空就返回
return;
// TODO: 在此处为本机数据添加绘制代码
//自定义二维坐标系
CRect rect;//创建矩形对象
GetClientRect(rect);//初始化矩形为客户区
pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式为各向异性的
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相对于客户区的位置发生改变,位于客户区新坐标原点右上方,可以将其平移恢复与客户区重合,否则后续如果需要继续使用rect属性如top,left等会出错
CPoint p0(-100, -100), p1(100, -100),p2(0, 200);//绘制三角形
pDC->MoveTo(p0);
pDC->LineTo(p1);
pDC->LineTo(p2);
pDC->LineTo(p0);
}
你要是不理解就把这个记住存下来当个模板用就行,以后写的时候直接复制上去就行通用的基本上
自定义坐标系绘制结果
未自定义坐标系结果