综述
在上一节我们学习了鼠标监听事件,在这里我们就利用它来做一个实例,对鼠标监听事件进行一个综合的应用。
要求
1. 绘制如下的机器人,并在此基础上进行创作 2. 对象创建:支持用户利用鼠标指定各个顶点位置,补充完整机器人的腿部。 3. 对象删除:支持用户选择一个腿部的多边形(与你的多边形保存的数据结构有关)并删除。 4. 对象存储:设计一种数据结构存储每个多边形的顶点与边,支持文件存盘,并支持读盘复原。 5. 支持用户选择多边形的颜色,支持用户移动多边形
成果
在这里为了动态演示,将我的成果以视频形式演示如下
[embed]http://cdn.cuiqingcai.com/robot.mp4[/embed]
好,欣赏完视频之后是不是非常想知道是怎样实现的呢?下面我们来一步一步进行讲解。
绘制半机器人
在前面的几篇中,已经详细描述了绘制机器人的方法,在这里我们简单贴一下代码来绘制一个半机器人。 直接上代码吧,不多说了
1 |
#include <glut.h> |
运行结果如下 这一步非常非常简单,如果有不懂的小伙伴请参见 此文章。
对象创建
通过上面的一步,我们已经可以轻松地绘制出一个半身机器人,接下来我们就要通过监听鼠标事件来实现动态多边形的绘制了。 因为实验要求中要求了多边形的颜色绘制,所以颜色怎么选取呢?我是这么想的,在面板的左上角绘制几个色块,通过鼠标点击这几个色块,读取出 RGB 值,然后相应地设置当前绘图的颜色即可。 所以首先我在左上角定义了几个颜色色块,同时监听鼠标事件。 首先定义几个颜色的 RGB 值
1 |
/* 各种颜色 */ |
然后定义一个绘制填充色的圆形的方法
1 |
/* 绘制填充的圆形 */ |
那么在 display 函数中,我们就可以调用下面的方法来绘制三个取色盘拾取颜色,其中最后一个取色盘保存了当前的颜色。
1 |
/* 绘制取色盘 */ |
这样光有了取色盘可不行,需要有鼠标点击事动态地改变取色的色值。现在我们可以加入鼠标监听方法如下 通过上一节的说明,我们定义一个 mouseClick 事件
1 |
/*鼠标点击事件 */ |
另外加入监听方法
1 |
/*鼠标点击事件,鼠标点击或者松开时调用 */ |
在这里有几个地方需要说明一下。
1.选项卡的分界范围是什么?
其实我是把整个画面分割成了三部分,其中最上面 40 像素的一个长条就是选项卡,选项卡又分为了两部分。左边是取色板,右边是绘制的选项,比如取点,绘制,删除等等的操作。所以,optionHeight 就指的是上面的 40 像素的分割线,optionWidth 是中间的分割线,即上方调色板和绘制选项点的分割线。 通过鼠标点击判断是在哪个范围内从而响应不同的事件。 从而鼠标监听事件就是下面的结构了
1 |
/* 如果在颜色选项卡中点击 */ |
其中第四个色板就是显示了当前的颜色,在-180,280 的位置绘制了当前的颜色色盘。并同时颜色值保存在了 nowColor 中。
2. halfHeight 和 halfWidth
这里定义了 halfHeight 和 halfWdith,在后面的绘图中会用到,同时在取色时也会用到,实际就是整个窗口宽高的一半,定义为全局变量即可。如当前的窗口是 600x600,所以现在二者就都是 300,300. 到现在,如果你按照流程走下来,代码是可以正常运行的,现在可以通过点击左上角的色盘进行取色,同时第四个色盘显示了当前的颜色。运行结果截图如下 好,接下来我们就进行多边形的定义了,多边形的定义我们利用结构体的形式,假设我们绘制的边数最大是 10,可以定义如下的多边形结构体,结构体中包含了顶点坐标(数组形式),顶点数量,颜色(RGB)。
1 |
/* 每个图形最多的顶点数 */ |
为了便于记录,我们定义一个 con 变量来记录当前绘制到了哪个多边形
1 |
/* 记录画了几个多边形 */ |
好,定义好结构体之后,我们就可以先选取点,然后绘制多边形了。所以在这里我们定义两个按钮,取点和绘制。 定义两个颜色
1 |
GLubyte startBtn[3] = {10, 10, 10}; |
我们可以用颜色来区分不同的按钮,现在原来的 display 函数中画上这俩按钮。
1 |
glColorCircle(250, 280, 10, startBtn); |
如图所示,当我们要取点的时候就可以点击一下左边的按钮,取完点后就可以点击右边的按钮完成绘制。 在鼠标监听事件中,当点击了左边的按钮,便开始拾取几个顶点,然后点击右边的按钮之后,会将图形绘制出来。所以为了区分当前是在拾取点还是完成绘制,我们定义一个状态变量叫 drawStatus
1 |
/* 绘制多边形的起始标志,0是开始绘制,1是结束绘制,初始为-1 */ |
在原来的 mouseClick 函数中,对于判断点击右上方选项卡的响应就可以改写如下
1 |
/*鼠标点击事件 */ |
其中 sameColor 方法就是来判断当前点击的位置是否和按钮颜色相等,在这里为了避免误差,我们像往常一样设置一个容差。
1 |
/* 判断两个颜色是否相等 */ |
好,当点击了第一个黑色按钮(取点的按钮)时,我们便可以在下方拾取点来保存到数组中了。 在最后的 else 代码块中加入如下的方法,用来取点。 这里的取点是取到了点击的坐标值,当前的 RGB 值,每取一个点,响应的 verNum(顶点数目)就加一。 而且当前保存到的多边形是 polygons[con],con 初始值为 0,也就是保存到第一个多边形结构体中。 当我们点击了开始绘制按钮时,con 会加 1,并且将保存的多边形绘制出来。
1 |
/* 如果当前是正在取点状态 */ |
到现在上面的 mouseClick 方法就变成了
1 |
/*鼠标点击事件 */ |
在这里有几点说明如下
1.glPoints 方法
即画点方法,为了直观地显示用户选取了哪个点,我们设置了这个画点的方法,每点一个点,就在屏幕上显示出来。 方法定义如下
1 |
/* 画点 */ |
在这里,glVertex2d 方法的参数为什么不是 x,y 呢?很简单,因为我们绘画时的坐标原点是窗口的中心点,而鼠标点击的坐标原点是左上角,为了做一个映射变换,x 需要减去 halfWidth,y 需要取反并加 halfWidth。总之定义这两个 half 变量还是用处多多的。
2.glutPostRedisplay
这个方法就是重新绘制的方法,我们看到在结束绘制的地方调用了这个方法,其实就是重新调用了 display 方法,所以为了让我们绘制的图形正常显示,我们需要在 display 方法中来绘制我们已经存储好的多边形。我们可以把绘制多边形定义为一个方法,然后在 display 中调用即可。 绘制多边形的方法如下
1 |
/* 绘制多边形 */ |
在 display 函数中调用一下即可,方法的最后面调用一下。
1 |
/* 绘制多边形 */ |
好,现在我们点击第一个黑色圆点,然后在屏幕上取点,取完点之后,然后点击右上角的黑色圆点,即可完成绘制 运行结果如下 在此先告一段落,下一篇我们接着这里来实现图形的删除,移动以及存盘,读盘等操作。
本节代码
到这里,提供如下代码,代码运行结果即为上图所示,由于代码太长,不完全展开显示,双击查看全部代码。
1 |
#include <glut.h> |
小伙伴们可以运行试试看。
综述
本节我们主要利用了鼠标时间来实现了取色,设置颜色,并成功通过取点绘制出了各种形状的多边形。