计算机图形学绘图软件Word格式.docx
《计算机图形学绘图软件Word格式.docx》由会员分享,可在线阅读,更多相关《计算机图形学绘图软件Word格式.docx(49页珍藏版)》请在冰豆网上搜索。
每一个C++设备环境对象都有相对应Windows设备环境,并通过一个32位类型的HDC句柄来标识。
CDC类的虚拟性使我们可以很容易的做到编写同时适用于多种设备的代码。
使用CDC类可以使我们的作图不用关心设备的问题。
CClientDC和CWindowDC是显示设备环境类,都是由CDC派生而来,区别在于CClientDC是窗口的客户区不包括边框、标题栏和菜单栏,(0,指客户区域的左上角。
0)CWindowDC的(0,0)指整个屏幕的左上角,这意味着我们可以在显示器的任意地方绘图,包括窗口边框、标题栏和菜单栏等等。
在编写鼠标绘图的代码之前,首先要确定如何用鼠标完成绘图。
以用鼠标绘制直线段为例:
首先将鼠标的光标移动到直线段的一个端点处,按下鼠标左键,然后按住鼠标左键不放,移动鼠标光标到直线段的另一个端点处,此时松开鼠标左键,就完成了用鼠标绘制直线段,应用程序会在两个端点之间绘制一条直线段。
绘制椭圆和椭圆区域比较类似,先后确定的是椭圆的外接矩形的两个对角点。
而对于绘制矩形区域,则确定的是矩形区域的两个对角点。
2.3、Bresenham算法
Bresenham算法1965年提出,基本原理是:
借助于一个误差量(直线与当前实际绘制像素点的距离),来确定下一个像素点的位置。
算法的巧妙之处在于采用增量计算,使得对于每一列,只要检查误差量的符号,就可以确定该下一列的像素位置。
2.4、鼠标
为了在应用程序中响应用户的鼠标动作,就需要在编写应用程序时选择响应鼠标消息并编写其对应的处理函数。
针对用户使用鼠标的一些基本操作,比如鼠标的单击、双击、移动等,Windows提供了相应的通用消息。
这些鼠标消息按照鼠标动作发生的区域可以分为两大类:
视图区鼠标消息和非视图区鼠标消息。
非视图区鼠标消息指鼠标光标在应用程序窗口视图区外的非视图区发生动作时产生的鼠标消息。
非视图区包括标题栏、最小化和最大化按钮、关闭窗口按钮、系统菜单栏和窗口框架等。
非视图区鼠标消息虽然用得比较少,但对于应用程序窗口的管理是有用的。
通过非视图区鼠标消息可以知道窗口何时进行移动、关闭或改变大小。
下表中列出了常用的非视图区鼠标消息及其含义:
非视图区鼠标消息
含义
WM_NCMOUSEMOVE
非视图区鼠标移动
WM_NCLBUTTONUP
非视图区鼠标左键抬起
WM_NCLBUTTONDBLCLK
非视图区鼠标左键双击
WM_NCLBUTTONDOWN
非视图区鼠标左键按下
WM_NCRBUTTONUP
非视图区鼠标右键抬起
WM_NCRBUTTONDBLCLK
非视图区鼠标右键双击
WM_NCRBUTTONDOWN
非视图区鼠标右键按下
视图区鼠标消息指鼠标光标在应用程序窗口视图区内发生动作时产生的鼠标消息。
视图区鼠标消息比较常用,用鼠标绘图就要使用视图区鼠标消息。
下表列出了常用的视图区鼠标消息及其含义:
视图区鼠标消息
WM_MOUSEMOVE
视图区鼠标移动
WM_LBUTTONUP
视图区鼠标左键抬起
WM_LBUTTONDBLCLK
视图区鼠标左键双击
WM_LBUTTONDOWN
视图区鼠标左键按下
WM_RBUTTONUP
视图区鼠标右键抬起
WM_RBUTTONDBLCLK
视图区鼠标右键双击
WM_RBUTTONDOWN
视图区鼠标右键按下
实现对鼠标消息的处理要完成以下工作:
(1)定义鼠标消息处理函数;
(2)使用消息映像宏实现鼠标消息和消息处理函数间的消息映像;
(3)编写鼠标消息处理函数的代码。
下表列出了视图区鼠标消息对应的消息映像宏及消息处理函数:
消息映像宏
消息处理函数
ON_WM_MOUSEMOVE()
afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);
ON_WM_LBUTTONUP()
afx_msgvoidOnLButtonUP(UINTnFlags,CPointpoint);
ON_WM_LBUTTONDBLCLK()
afx_msgvoidOnLButtonDblClk(UINTnFlags,CPointpoint);
ON_WM_LBUTTONDOWN()
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
ON_WM_RBUTTONUP()
afx_msgvoidOnRButtonUp(UINTnFlags,CPointpoint);
ON_WM_RBUTTONDBLCLK()
afx_msgvoidOnRButtonDblClk(UINTnFlags,CPointpoint);
ON_WM_RBUTTONDOWN()
afx_msgvoidOnRButtonDown(UINTnFlags,CPointpoint);
其中消息处理函数的参数point是CPoint对象,它存储了产生鼠标消息时鼠标光标所处位置的坐标,如鼠标左键按下的处理函数中传入的point参数中存放了鼠标左键按下位置的坐标。
参数nFlags是一个无符号数,它表明了在鼠标消息产生的时候鼠标按钮及部分键盘按键的状态,其值可为下表中值的任意组合:
nFlags参数值
说明
MK_CONTROL
Ctrl键按下
MK_LBUTTON
鼠标左键按下
MK_MBUTTON
鼠标中键按下
MK_RBUTTON
鼠标右键按下
MK_SHIFT
Shift键按下
◆SetCapture函数,用于捕捉鼠标,其函数声明如下:
CWnd*SetCapture();
该函数是窗口基类CWnd的成员函数,因为CView类是从CWnd类派生而来的,所以它也拥有该函数。
该函数返回捕捉了鼠标的窗口指针。
执行该函数后,视图类就捕捉了鼠标,此后的鼠标动作都将产生视图区鼠标消息。
◆ReleaseCapture函数,用于释放鼠标,其函数声明如下:
BOOLReleaseCapture();
该函数用于释放被捕捉的鼠标。
在用鼠标绘图完毕后,需要调用该函数释放鼠标,否则窗口将不能正确接受鼠标消息。
除了在鼠标绘图开始时捕捉鼠标之外,也可以通过调用ClipCursor函数将鼠标限制在指定区域中以避免在鼠标绘图过程中出现不同类型的鼠标消息。
◆ClipCursor函数,用于将鼠标限制在指定的矩形区域中,其函数声明如下:
BOOLClipCursor(CONSTRECTlpRect);
参数lpRect指向一个RECT结构体,该结构体定义了一个矩形区域,该函数将鼠标限制在此矩形区域中。
如果鼠标光标要移动到矩形区域外,系统将自动调正鼠标光标位置,使其始终在指定的矩形区域内。
通常用如下代码把鼠标限制在应用程序窗口的视图区内:
CRectrect;
//矩形区域对象
GetClientRect(&
rect);
//获得并保存窗口视图区区域坐标
ClientToScreen(&
//用视图区区域坐标重新计算屏幕坐标
ClipCursor(&
//限制鼠标在窗口视图区中
上面的代码将鼠标限制在窗口的视图区中,这样鼠标只能在视图区中产生动作,也就只会产生视图区鼠标消息。
其中用到的GetClientRect函数和ClientToScreen函数都是CWnd类的成员函数。
◆GetClientRect函数,用于获得窗口视图区的矩形区域坐标,其函数声明如下:
voidGetClientRect(LPRECTlpRect)const;
该函数将窗口的视图区的左上角和右下角坐标存放在lpRect指针指向的矩形区域结构中。
◆ClientToScreen函数,用于将传入的矩形区域坐标或点坐标转化成实际的屏幕坐标,其函数声明如下:
voidClientToScreen(LPPOINTlpPoint)const;
voidClientToScreen(LPRECTlpRect)const;
参数lpPoint和lpRect分别指向点结构和矩形区域结构,该函数将传入的点的坐标或矩形区域的坐标(左上角点和右下角点坐标)转换成实际的屏幕坐标,这样调用ClipCursor函数时才能将鼠标限制在正确的区域中。
被限制的鼠标在绘图完毕后应该取消限制,采用如下语句来完成取消对鼠标的限制:
ClipCursor(NULL);
限制鼠标移动范围会加大系统负担,所以通常不采用此种方法。
在用鼠标绘制图形时,我们希望修改鼠标光标形状,而不是使用默认的斜箭头光标。
鼠标的光标形状由专门的光标(Cursor)资源所决定。
我们可以在资源面板上向项目中添加光标资源(在添加资源对话框中有光标资源类型,如图2.3所示),每个光标资源对应一个唯一的资源ID,应用程序框架通过该ID来识别光标资源。
要使用光标资源作为鼠标的光标形状,需要首先将光标资源加载到系统中,然后再设置鼠标光标形状为加载的光标资源的形状。
◆LoadCursor函数,用于加载光标资源,其函数声明如下:
HCURSORLoadCursor(LPCTSTRlpszResourceName)const;
HCURSORLoadCursor(UINTnIDResource)const;
参数lpszResourceName和nIDResouce分别为光标资源的名称和ID号,函数将指定的光标资源加载到系统内存中。
函数返回光标资源句柄(HCURSOR)。
◆LoadStandardCursor函数,用于加载Windows预定义的光标资源,其函数声明如下:
HCURSORLoadStandardCursor(LPCTSTRlpszCursorName)const;
参数lpszCursorName是由一些以IDC_开头的光标资源名称,用来指定Windows预定义的光标资源,下表中列出了预定义的光标资源名称和对应的光标形状:
预定义的光标资源名称
光标形状
IDC_ARROW
标准的斜箭头光标
IDC_IBEAM
标准的插入文本光标
IDC_WAIT
沙漏形状的光标
IDC_CROSS
标准的十字光标
IDC_UPARROW
向上方向的箭头
IDC_SIZEALL
带有四个方向箭头的光标
IDC_SIZENSWE
带有左上和右下方向箭头的光标
IDC_SIZENESW
带有右上和左下方向箭头的光标
IDC_SIZEWE
带有左右方向箭头的光标
IDC_SIZENS
带有上下方向箭头的光标
该函数同样返回光标资源句柄。
上面两个加载光标资源的函数都是应用程序基类CWinApp的成员函数,在视图类中要使用该函数,需要调用AfxGetApp()函数获得应用程序基类的指针,然后再调用加载光标资源函数。
加载完光标资源后,调用SetCursor函数设置使用光标资源。
2.5、SetROP2
WindowsAPISetROP2(intnDrawMode)主要用于设定当前前景色的混合模式。
R2_NOT就是取反的意思,即前景色为背景色的反色,经常用R2_NOT来画橡皮线,因为两次取反可以还原背景色。
根据nDrawMode设置的方式重新设定绘图的方式,下面就不同的nDrawMode值具体解释绘图模式是如何改变的。
首先就nDrawMode的取值有以下的情况:
1、R2_BLACKPixelisalwaysblack.//所有绘制出来的像素为黑色
2、R2_WHITEPixelisalwayswhite.//所有绘制出来的像素为白色
3、R2_NOPPixelremainsunchanged.//任何绘制将不改变当前的状态
4、R2_NOTPixelistheinverseofthescreencolor.//当前绘制的像素值设为屏幕像素值的反,这样可以覆盖掉上次的绘图,(自动擦除上次绘制的图形)
5、R2_COPYPENPixelisthepencolor.//使用当前的画笔的颜色
6、R2_NOTCOPYPENPixelistheinverseofthepencolor.//当前画笔的反色 //下面是当前画笔的颜色和屏幕色的组合运算得到的绘图模式。
7、R2_MERGEPENNOTPixelisacombinationofthepencolorandtheinverseofthescreencolor(finalpixel=(NOTscreenpixel)ORpen).//R2_COPYPEN和R2_NOT的并集
8、R2_MASKPENNOTPixelisacombinationofthecolorscommontoboththepenandtheinverseofthescreen(finalpixel=(NOTscreenpixel)ANDpen).//R2_COPYPEN和R2_NOT的交集
9、R2_MERGENOTPENPixelisacombinationofthescreencolorandtheinverseofthepencolor(finalpixel=(NOTpen)ORscreenpixel).//R2_NOTCOPYPEN和屏幕像素值的并集
10、R2_MASKNOTPENPixelisacombinationofthecolorscommontoboththescreenandtheinverseofthepen(finalpixel=(NOTpen)ANDscreenpixel).//R2_NOTCOPYPEN和屏幕像素值的交集
11、R2_MERGEPENPixelisacombinationofthepencolorandthescreencolor(finalpixel=penORscreenpixel).//R2_COPYPEN和屏幕像素值的并集
12、R2_NOTMERGEPENPixelistheinverseoftheR2_MERGEPENcolor(finalpixel=NOT(penORscreenpixel)).//R2_MERGEPEN的反色
13、R2_MASKPENPixelisacombinationofthecolorscommontoboththepenandthescreen(finalpixel=penANDscreenpixel).//R2_COPYPEN和屏幕像素值的交集
14、R2_NOTMASKPENPixelistheinverseoftheR2_MASKPENcolor(finalpixel=NOT(penANDscreenpixel)).//R2_MASKPEN的反色
15、R2_XORPENPixelisacombinationofthecolorsthatareinthepenorinthescreen,butnotinboth(finalpixel=penXORscreenpixel).//R2_COPYPEN和屏幕像素值的异或
16、R2_NOTXORPENPixelistheinverseoftheR2_XORPENcolor(finalpixel=NOT(penXORscreenpixel)).//R2_XORPEN的反色
总之,上述api的一个作用是在需要改变绘图的模式时,不需要重新设置画笔,只需要设置不同的绘图的模式即可达到相应的目的。
3、内容与步骤
3.1工程的新建
打开MicrosoftVisualC++6.0—>
点击File—>
New在Projects中选择MFCAppWizard(exe);
在Projectname中输入工程的名字Graphic,在Location中选择工程存放的路径。
填完后点击OK按钮。
(如图1)填完后点击OK按钮,弹出对话框(如图2)。
在弹出来的对话框中我们可以选择生成三种不同类型的应用程序:
单文档、多文档、对话框。
单文档程序如记事本,在一个应用程序中只能对一个文档进行操作,降低了编程的复杂度并减少了运行程序时所需的资源。
对某些小型应用(比如文本编辑器或小型图像编辑器)可以采用这种类型的窗口应用程序。
多文档程序如PhotoShop,在一个应用程序中可以同时对多个文档进行操作;
对话框程序如QQ,应用程序的界面是对话框形式的。
现对话框版本的程序更小一些。
除了节省资源外,对话框版本的应用程序的加载速度也更快些。
基于对话框的应用程序比完成相同功能的基于窗口的应用程序更简单有效。
这里我们选第一个:
单文档。
选择完后点击Next,设置默认,最后点击Finish完成工程的创建。
图1
图2
3.2单文档
生成单文档程序后,进行编译,在运行,我们可以看到以下的结果。
如图3
图3
在ClassView中,我们可以看到系统自动为我们生成了五个类:
CApp,CDoc,CView,CAboutDlg,CMainFrame。
如图4
图4
CApp相当于C语言中的main()函数。
是程序的起始。
CDoc是用于处理程序中文档的类。
CView主要是处理客户区的可视化的操作的类。
CAboutDlg是处理关于对话框的类。
CMainFrame是非客户区的一些资源的类。
我们主要是对CView类进行操作。
3.3详细设计
首先,在Toolbar中建立新的工具条IDR_DRAW。
如图5
图5
在新建的工具条中建立如图6所示图标,并分别命名为ID_DRAWLINE、ID_DRAWZHILINE、ID_DRAWELLIPSE、ID_DRAWFANG、ID_DRAWELLIPSESHI,ID_DRAWFANGSHI、ID_XIANGPI、ID_DRAWFILL、ID_DRAWRED、ID_DRAWBLACK、ID_DRAWG、ID_Color。
分别是画笔、直线、椭圆、长方形、实心椭圆、实心方、橡皮、种子填充、红色、黑色、绿色、颜色。
图6
新的工具条创建完毕,此时如果我们运行应用程序,会发现该工具条并没有显示出来,这是因为我们还没有编写代码将该工具条加入到应用程序窗口中。
下面我们来看一下如何将工具条加入到应用程序窗口中。
首先,选择类面板,双击CMainFrame节点,在右侧的编辑区中将打开CMainFrame类的头文件。
这里声明了一个CStatusBar类对象变量m_wndStatusBar和一个CToolBar类对象变量m_wndToolBar。
它们分别对应了系统自动添加的默认状态栏和默认的初始工具条。
然后,该对象将用于与绘图工具条对应。
在类面板中双击CMainFrame节点下的OnCreate节点,在编辑区打开CMainFrame类的CPP文件,并定位到该类的OnCreate成员函数处。
该成员函数在主窗口创建的时候调用,在此函数中可以给主窗口添加工具条和状态栏。
再次添加如下代码:
//创建绘图工具条
if(!
m_DrawToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP
|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)||
!
m_DrawToolBar.LoadToolBar(IDR_DRAW))
{
TRACE0("
Failedtocreatetoolbar\n"
);
return-1;
//failtocreate
}
//设置绘图工具条的停放状态
m_DrawToolBar.EnableDocking(CBRS_ALIGN_ANY);
//在主窗口中放置绘图工具条
DockC