![计算机图形学:原理、算法及实践](https://wfqqreader-1252317822.image.myqcloud.com/cover/947/23400947/b_23400947.jpg)
2.2 VC++基本图素的绘制方法
2.2.1 相关类及函数
在实现计算机图形学的原理和算法时,会用到VC6.0中的相关类、函数、数组、头文件以及模板等,本节对此进行简单介绍。
CPoint point——存放视图窗口像素点的坐标,其中point.x是水平方向的x坐标值,point.y是垂直方向的y坐标值。
COLORREF crColor——像素点的颜色值类,可以直接写为RGB(r,g,b),r、g、b分别对应三基色中的红色值、绿色值和蓝色值,取值范围在0~255之间。其中RGB(255,0,0)是红色,RGB(0,255,0)是绿色,RGB(0,0,255)是蓝色,RGB(255,255,255)是黑色。
COLORREF SetPixel(intx,inty,COLORREF crColor)——在绘图窗口的绘制点的函数,x和y是点的x坐标和y坐标,crColor是该点的颜色。例如pDC->SetPixel(x,y,RGB(255,0,0));命令在视图窗口的(x,y)点会绘制一个红色的点。
为了在视图窗口拾取多个点,可以利用集合类CArray来保存这些点。CArray是模板类,使用前需要加入模板类的头文件afxtempl.h。例如,在视图类中使用CArray,则在视图类的头文件CGTest001View.h中加入模板类的头文件afxtempl.h:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P31_17144.jpg?sign=1739516825-ewQ2tXC7HwPAsShlz2dNPB4DaHjSb1Tc-0-c4f1c827b12c9514fc1ef8832ba584f7)
使用时,首先在视图类头文件CGTest001View.h中声明点集的对象,如:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P32_17146.jpg?sign=1739516825-l5VdnSQbi91CfR7b8oaoHtt5D9lRcdIS-0-6db021f3ca06a9bfe7958b656af982ed)
CArray中常用的相关函数如下:
m_pt_array.Add(point)——在集合尾部增加一个元素(例如,增加一个点);
m_pt_array.GetSize()——计算集合的长度;
m_pt_array.GetAt(i)——得到第i位元素,从第0位开始;
m_ptarray.RemoveAt(i)——删除集合中某个索引位置的元素;
m_ptarray.RemoveAll()——将集合内的所有元素都清空;
m_pt_array.Append(m_array)——复制另外一个集合的元素到当前的集合中。
在程序中使用数学运算时,需要加入支持数学计算函数的头文件:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P32_17147.jpg?sign=1739516825-OoIByzS1t6F9RQ6g88VZ4AUofXjdmcr1-0-141134ca29f1cbe9d7103e8bfcac61ae)
2.2.2 基本像素点的交互式绘制方法
为了达到方便的交互效果,可以利用鼠标在视图窗口拾取像素点,然后记录和实时显示这些像素点。例如,每单击一次,就将该点记录在点的集合里,记录点的代码在左键单击函数OnLButtonUp()中实现,并调用OnDraw()函数,将点集中的点显示出来。OnLButtonUp()和OnDraw()中的代码分别如下:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P32_17148.jpg?sign=1739516825-izGdZ95u5jvWPupYOZPu6vE6JriXnOYf-0-c9926fa41588cb2a86f27be824735e10)
执行程序,在视图窗口每单击一次,就会以红色显示鼠标所在点,并显示该点的坐标值,如图2.2-1所示。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P33_6913.jpg?sign=1739516825-SiijEGTCNKkqroywfdLk3MH4glbN5mTj-0-c5d3200e32bcc9551b8bc872a895916a)
图2.2-1 交互式绘制像素点
2.2.3 非模式对话框交互式实现方法及颜色对话框的使用
在进行计算机图形原理和算法编程时,可以采用非模式对话框实现图形实时交互。非模式对话框是指在对话框打开的同时,其他窗口还能够继续操作。非模式对话框的创建方法如下。
首先,在菜单栏中选择“插入”→“资源”命令,选择“资源类型”对话框,在新建的对话框上单击鼠标右键,选择“属性”,打开对话框属性设置窗口,在“常规”选项卡中可以修改对话框的ID,例如IDD_MDLG,在“更多样式”选项卡中,选中“可见”复选框,如图2.2-2所示。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P34_6923.jpg?sign=1739516825-ohYranyDZQXH9TvJIMs9C6XgiUB44NX1-0-d12ff3a43905054cc598a5b06260cafd)
图2.2-2 对话框属性设置
在对话框上双击,或者右击,从弹出的快捷菜单中选择“建立类向导”命令,为创建的对话框生成类和类文件,例如,类名为CCMDlg,则生成的对应类头文件和源文件分别为CMDlg.h和CMDlg.cpp。
在CMDlg.h头文件的对话框类中手动添加对话框基类的Create()函数:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P33_17149.jpg?sign=1739516825-E8wDvSpmzU5YuwP852BbSP1qDwizSJAU-0-1a7a7eff0fdfc69a5c9522be33dc2448)
在CMDlg.cpp执行文件中添加该函数的实现代码:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P33_17150.jpg?sign=1739516825-1ppl3KzqSWjF99N1VQg37PuPsTvCFDqj-0-07fbde39adf5339fdd19090903ec3223)
当在视图类中使用该对话框时,首先在视图类定义的代码前加入对话框的头文件:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P33_6920.jpg?sign=1739516825-2FDPjmNQYy0rwe7Pt2RtDfqDmHYfhedi-0-f7d42e1fcc0e82e56edf842f33ea8d4d)
并在类中定义对话框的指针变量:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P34_17155.jpg?sign=1739516825-3iLjdvSgGLaBTKEeVuJx2nSV7OIICkTI-0-1027094b9bef184bbacc064035d32c4e)
然后,在视图类CGTest001View.cpp的类构造函数中,建立该对话框对象指针:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P34_17154.jpg?sign=1739516825-7IY8U0ibm8QsdUVN55Gce5gCkusG7YYT-0-f55b2218a53cea0e9389dfae8de06ad2)
并在析构函数中,删除建立的对话框对象指针:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P34_17156.jpg?sign=1739516825-OD2Ablc14npMQDLzamvgmK3Q4imtUJI3-0-ee562c830dc6ceb9e44923901137df03)
可以通过菜单项或者工具栏打开对话框。例如,利用工具栏打开对话框,在视图类里,建立工具栏的消息映射函数(方法见上节),在工具栏的消息映射函数里判断对话框是否创建,如没有创建,则创建;如已创建,则显示。代码如下:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P34_17157.jpg?sign=1739516825-4iaDZ8AVUT4dtai1Ka2EUdr30mZ7YtnO-0-965ef235e2fa0fb6b55f9e4f503aa50f)
执行程序,打开软件,单击工具栏上的图标,即可打开对话框,如图2.2-3所示,这时仍可在视图窗口操作。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P35_6960.jpg?sign=1739516825-hsDmsYe0GvYhNsu4AGUNCGnq6wiA89xb-0-4999815592f45f8e15a1040f91298846)
图2.2-3 创建非模式对话框
视图窗口的数据可以传入到对话框中。例如,将视图窗口上点的坐标传到对话框中,首先在对话框中放入两个从控件中拖入的编辑框来显示坐标值,ID分别为IDC-EDITX和IDC-EDITY,通过在菜单栏中选择“建立类向导”→在Member Variables选项卡中选择对话框类,分别选中两个编辑框ID,单击“Add Variable...”按钮,如图2.2-4所示,为两个编辑框建立变量名m_X和m_Y,变量类型都是int整型。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P36_6994.jpg?sign=1739516825-gphh1FsQCQKq2z8RTl00I85w88shClTz-0-3ff3a6050967b359375ddb8d5ee5b032)
图2.2-4 建立变量
在视图窗口单击时,如果对话框是创建好的,则把当前点的坐标值赋给对话框里的编辑框,并实时显示出来。代码如下:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P35_17159.jpg?sign=1739516825-8Uq9gzaioyWcqMw7Q2H8hqgss3as4mvE-0-dc291e7b77ddf15445d2dfab4460dbf0)
执行程序,当在视图窗口单击时,当前点的坐标值会实时显示在对话框中,如图2.2-5所示。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P36_6997.jpg?sign=1739516825-cK1Ir6j4h1diERKaPtreK6cuqkSx4j4P-0-440a2041c333bc1fe48b3697cccde265)
图2.2-5 对话框实时显示视图窗口的数据
如果要把对话框里的数据传给视图窗口,则在对话框类中加入视图窗口的类变量,通过视图窗口的类变量把对话框的数据赋给视图窗口。首先,在对话框类头文件CMDlg.h中添加视图窗口类的引用:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17160.jpg?sign=1739516825-i0YkqGvpKWDFFQN7lSKcP8X6BFHfF0yY-0-e4fca31aa93bac97b4351fff28e33678)
并在CCMDlg类中增加视图窗口类指针变量:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17161.jpg?sign=1739516825-BK5Q1QWOExT3DGdTuSSv9qnTwT6FtZUy-0-c21a8f623989cdf21f53eaf9cf06f90b)
在源文件CMDlg.cpp增加对视图窗口类文件的引用:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17162.jpg?sign=1739516825-opswHxnP7vCbdICp0cd4GFOiyybxehWd-0-6e439382bc716210e98b1aee5577156b)
在视图窗口类CCGTest001View的构造函数中,在声明创建对话框后,还需要将视图窗口类的指针赋给对话框类中的视图窗口类变量:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17163.jpg?sign=1739516825-U5bGGJ4OhJI4cv4OF3mLYAagl3MUfPvp-0-9bec4809e34bd51511399db2c67e4055)
进行上述设置后编译程序,如果出现关于GetDocument的相关错误,还需要在CGTest001View.h中增加对CCGTest001Doc文档类的引用:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17164.jpg?sign=1739516825-ncKqCRv5eQJezTkLwc1oU3D30GzRrslI-0-73af0e18ebc2e59d9a2693a6b705227a)
这样,对话框中的视图窗口对象就和当前的视图窗口建立了联系。在对话框中输入点的坐标值,通过“确定”按钮的消息函数,就将该坐标值传给视图窗口的点集合中,并显示出来:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P37_17165.jpg?sign=1739516825-nm1MPnMY2sbg6Gir4itrzX9pASSftlo1-0-3ad1a674a191118eb1e45cfe919adb0a)
程序执行效果如图2.2-6所示。单击“确定”按钮就可以把对话框中的坐标值加入点集合中,并在视图窗口显示出来。使用上述方法就可以实现对话框和视图窗口的双向交互。
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P38_7038.jpg?sign=1739516825-WTJmgSrUvvGxyL82hEGPPY0AAZhliwDi-0-84ad1cbf29df98208bc182e30f227b1a)
图2.2-6 对话框中数据在视图窗口显示
在应用程序中绘制图形时,会为图形设置各种颜色,可以直接调用类似RGB(0~255,0~255,0~255)这个结构来设置颜色,也可以通过VC6.0提供的颜色对话框类CColorDialog获取颜色。CColorDialog对话框对象通过DoModal()函数直接打开,然后通过调用CColorDialog的一个结构体m_cc的成员rgbResult来获取选定的颜色值,再将这个值保存在设定的颜色变量中,就可以利用这个变量来设置颜色。代码如下:
![](https://epubservercos.yuewen.com/BFC8F2/12023547903396406/epubprivate/OEBPS/Images/Figure-P38_19396.jpg?sign=1739516825-x7aIPqg0xrZVxfAXtmkd2OUmvoV4bVr3-0-356300f1666e2b2597e4a79312ca841f)