目录1、需求与功能分析 (1)2、系统总体框架 (2)3、模块设计与分析 (3)3.1画图模块 (3)3.2贴图模块 (3)3.3窗口模块 (4)3.4菜单模块 (4)3.5工具栏与状态栏模块 (4)4、类的设计与分析 (4)4.1、CAboutDlg类 (4)4.2、CChildFrame类 (4)4.3、CDib类 (4)4.4、CDrawingDoc类 (5)4.5、CDrawingView类 (6)4.6、CMainFrame类 (7)4.7、CSettingDlg类 (7)5、特色算法分析 (8)5.1 CDib类中的显示bmp位图 (8)5.2 CDrawingView类中的画图部分 (10)6、功能测试 (13)7、存在的不足与对策 (16)8、程序源代码 (17)9、使用手册 (17)10、参考文献 (20)1、需求与功能分析为了检验一个学期以来自己学习c++这门课程能够学到多少知识,加上原来就对图像处理就比较感兴趣,曾经更有想过要做一个可以合成红蓝3D图片的一款软件,就是那种需要带上红蓝眼镜才可以看到3D效果的那种图片,自己也有用photoshop做过这样的图片,但是photoshop需要调很多东西才能合成这样的图片,而且还要用相机送两个不同的角度拍两张照片作为源图片去合成红蓝3D图片,虽然我知道原理并不难,但是当我选择了”简易绘图程序”这个课程设计的题目之后,才发现每实现一个功能都需要花很多的精力,而且实现那些功能之后还会发现各种各校的bug,需要细心去寻找解决的办法。
如今课程设计也要上交,一样还有很多我想实现的功能都还没实现,最终也没有实现我想要实现的功能---合成红蓝3D图片。
只做了一些简单的绘图功能。
功能分析,目前这个软件的主要功能有如下:1、画直线:通过OnLine()函数实现。
2、画矩形:通过OnRectangle()函数实现。
3、画椭圆:通过OnEllipse()函数实现。
4、铅笔工具:可以画任意线条。
通过OnPencil()函数实现。
5、橡皮擦:可以擦除所画的线条。
该功能还没实现。
6、右键弹出菜单:可以在客户中点击鼠标右键,快速选择常用菜单。
通过OnContextMenu函数实现。
7、状态栏显示鼠标移动的坐标:在程序的右下角显示,通过OnUpdateX(CCmdUI*pCmdUI)和OnUpdateY(CCmdUI *pCmdUI)这两个函数实现。
8、画图颜色选择:可以画任何颜色的线条,通过OnEditColor()函数实现。
9、读取bmp位图:可以在电脑中选择一个bmp位图,在程序中显示出来,通过新建一个Cdib类来读取bmp文件信息再view类和Doc类调用来显示该位图。
10、保存为bmp位图:可以将在程序所画的图形保存为一幅bmp图片,通过view中的SaveAsBmp(CString filename)实现。
11、线条类型及线宽的设置:可以将画出的线条设置成实线、虚线、点线,还可以设置线条的粗细,通过示例这一功能可以立刻显示所选择线条的粗细及线型。
通过新建CSettingDlg类,再在view类中调用OnSetting()函数实现画笔的对话框,CSettingDlg类中的OnPaint()函数是实现示例功能的。
12、窗口的重绘时不擦除原来的内容:可以在窗口发生变化时,窗口的内容不消失,程序在窗口尺寸发生变化时,将会发送WM_PAINT消息,这时首先会擦除窗口背景,然后进行重绘操作,这样就把窗口中先前绘制的内容擦除了。
我是使用双缓冲来解决这个问题的,双缓冲设计思路:如果只是为了让窗口闪烁不那么厉害,避免背景色的填充是最直接的办法。
但是那样的话,窗体上会变的一团糟。
因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。
所以单纯的禁止背景重绘是不够的。
我们还要进行重新绘图,但要求速度很快,于是想到了使用 BitBlt函数。
它可以支持图形块的复制,速度很快。
我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。
以上就是双缓冲绘图的基本的思路。
一部分代码写在了OnLButtonUp(UINT nFlags, CPoint point)函数里面,也有一部分打码写在了OnDraw(CDC* pDC)函数里面。
2、系统总体框架图1 总体框架3、模块设计与分析3.1画图模块:该模块的大部份功能都写在了view类里面,这样造成了后期的修改造成了一定的影响,对于排错,修复bug增加了难度,对于初次使用mfc 做一个相对大一点的程序,在函数分配,类的建立都有很多不足的地方。
该模块也是此次程序的重点模块之一,主要负责画一些简单图形,例如:直线、矩形、椭圆、任意曲线(铅笔)等等;有线型、线宽的设置;还有画笔颜色的选择,可以画各种各样颜色的线条。
该模块的设计思路是:简易画图工具——线型、线宽设置——颜色选择。
3.2贴图模块:该模块是为了读取bmp位图设计的,主要代码写在CDib类里面,再通过view类和Doc类去调用显示位图,这个模块同样是此次程序的重点模块之一,也是花费时间最多的一个模块,开始的时候,我使用了读取程序里面的位图资源,但是这样的办法虽然能够成功显示出位图,但是却十分麻烦,就是要先把想要显示的位图放到程序的位图资源里面,然后再通过LoadBitmap函数把位图资源加载到程序再显示出来。
这样对使用都来说是非常不合理的,但是我却从这里懂得了一个显示位图的思路,要显示一幅位图需要有以下几点:(1)读取bmp位图信息,bmp位图的信息包括:位图文件头BITMAPFILEHEADER 和位图信息头BITMAPINFOHEADER,还有就是颜色表RGBOUAD。
最后一部分是实际的位图数据IMAGEDATA。
(2)创建兼容DC,这和相对比较容易,通过CreateCompatibleDC函数创建。
(3)将位图选入兼容DC中,也就是先把位图存到内存之中,通过SelectObject 函数实现。
(4)将兼容DC中的位图贴到当前DC中,也就是显示在屏幕上,通过BitBlt 或者StretchBlt这两个函数都可以实现,区别在于,前者不可以自动压缩图片在一个窗口显示全部的图片内容,而后者可以。
后来我在另一本书上看到了其它的方法,也了解了DDB(设备相关图)和DIB(设备无关图),DDB位图的格式相当依赖于设备,所以它不适用于图像的交换,所以,大部分的BMP位图都会包含DIB。
为了完成位图的显示,需要完成:装载位图、获取位图文件头信息、获取位图信息、获取颜色表信息、获取做准备数据信息、获取位图尺寸、获取颜色总数、获取颜色位数、创建位图调色板、绘制位图等等。
但是windows并没有提供DIB操作的类,需要自己动手写一个CDib的类,虽然这个类网上有可以直接复制,但是我还是按照书本那里,自己跟着课本的思路,手动把代码写上去,所以花费的时间比较多,即使是这样,有一些还是没有完全理解。
封装好CDib类之后,再在View类和Doc类中写上相应的调用函数。
便可以在程序中通过“打开”从磁盘中读取bmp位图了。
设计思路基本上和上面的步骤一样。
此时还需要面临另外一个问题,就是窗口的重绘。
此功能已在功能分析上有说明,就是利用双缓冲解决这个问题。
3.3窗口模块:这部分大多数都是编译器自动生成,只做了一些修改,例如:使程序一开始运行便最大话,还是自定义程序的标题。
刚开始做的时候,创建成单文档的了,后来需要用到多文档的,然后又不想再重新做过,所以只能手动修改,把单文档改成了多文档的。
新建一个多文档的程序,然后用旧的那个单文档对照着多文档的源代码,一个个类的修改。
3.4菜单模块:该部分同样大部分都是编译器自动生成的,自己增添了一部分菜单例如:绘图工具、颜色设置、线条设置等等。
还有右键弹出菜单,有新建窗口、颜色及线条设置、退出程序等等,让使用者可以进行快速的操作。
3.5工具栏与状态栏模块:除了编译器自动生成的之外,还加入了画直线、矩形、椭圆、铅笔等工具的快速选择,状态栏可以显示鼠标移动的坐标。
该部分让我觉得有点难度的就是那些工具栏那些图标,我画了很久才画出那个铅笔的图标,听说可以从磁盘里加载这些图标的,但是我不知道怎么要怎么做。
4、类的设计与分析4.1、CAboutDlg类由编译器生成,只做了两处的修改:m_pMainWnd->SetWindowText(_T("简单绘图工具")); //设定主框架窗口标题pMainFrame->ShowWindow(SW_MAXIMIZE); //显示主框架窗口默认最大化4.2、CChildFrame类由编译器生成,只做了一处的修改:cs.style |= WS_VISIBLE|WS_MAXIMIZE; //使子窗口一打开就是最大化4.3、CDib类按照书本上的代码进行封装,以下是各成员函数和数据成员4.4、CDrawingDoc类由编译器生成,添加不少内容:因为显示bmp位图时,有一部分操作需要在这里进行,首先在头文件中添加了以下:public:HGLOBAL GetHObject() const { return m_hDIB; } //获取DIB对象的句柄CPalette *GetDocPal() const { return m_palDIB; } //获取调色板指针CSize GetDocDimension() const { return m_sizeDoc; } //获取调色板大小void UpdateObject(HGLOBAL hDIB); //更新DIB对象void SetDib(); //初始化DIB对象protected:HGLOBAL m_hDIB; //定义指向DIB的句柄变量CPalette *m_palDIB; //定义指向逻辑调色板的指针CSize m_sizeDoc; //文档大小的变量4.5、CDrawingView类编译器自动生成的类,全部的画图操作都在此类中完成,包括bmp位图的显示也是在该类中通过调CDib类中的函数来完成的。
4.6、CMainFrame类主要同编译器生成,修改小部分:static UINT indicators[] ={ID_SEPARATOR, // status line indicatorID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,ID_X,ID_Y};ID_X,ID_Y是状态栏中的x和y坐标.cs.style&=~FWS_ADDTOTITLE; //使主窗口的标题不发生变化4.7、CSettingDlg类由自己创建,主要是响应菜单中的各个设置选项,该类实现的功能比较少。