EasyX 鼠标点击事件监听的一种优雅实现
最近,学校课程要求使用EasyX 实现一个小游戏或者小应用。但是无论是游戏还是应用,监听鼠标点击,并判断鼠标点击到了那里,并对此做出相应的响应都是不可避免的一个场景。
是的,这是个非常简单的场景,想要实现也没啥难度。参照学校给的例子和网上找到的一些实现对此的处理,基本上代码如下所示:
if (msg.uMsg==WM_LBUTTONDOWN) // 如果点左键
{
if((msg.x>110 && msg.x<360) && (msg.y>240 && msg.y<310))// 点击菜单1
choose='1';
if((msg.x>110 && msg.x<398) && (msg.y>325 && msg.y<390))// 点击菜单2
choose='2';
if((msg.x>110 && msg.x<458) && (msg.y>410 && msg.y<475))// 点击菜单3
choose='3';
if((msg.x>110 && msg.x<332) && (msg.y>500 && msg.y<550))// 点击菜单4
choose='4';
}
当我第一眼看上去,啊这,不是吧。就这样写??
那我斗地主一个人17张牌个个这样写还得了?(是可以用循环简化,但是我还有一堆分布在天南海北的按钮),而且这样用 if 绝对不是我高某人的风格。于是,我就去睡觉了,毕竟梦里啥都有。
别别别,把刀收回去… 不睡了,不睡了,没有困难的任务,只有勇敢的当代大学牲!办他…
首先我们把所有,可以被点击的“东西”所共同拥有的特性抽象出来, 首先他可以被点击, 被绘制(既然可以被绘制那么肯定拥有下x, y坐标, 长度和宽度)所以这样一个类就被我们抽象出来了。
class Clickable
{
public:
int x;
int y;
int height;
int width;
void(*clickAction)();
void receiveEvent(int cx, int cy);
virtual void draw() = 0;
private:
bool isClickMe(int cx, int cy);
};
我相信x, y, height,width 不用多说。首先说一下,
- clickAction这是一个函数指针,他是 控件 被点击后所执行的操作。
- receiveEvent 是一个函数他负责通知控件用户点击了哪里
- isClickMe 是一个私有函数,他主要负责判断用户是否点击到控件
具体实现如下:
void Clickable::receiveEvent(int cx, int cy)
{
if (isClickMe(cx, cy))
{
clickAction();
}
}
bool Clickable::isClickMe(int cx, int cy)
{
return cx >= x && cy >= y && x + width >= cx && y + height >= cy;
}
下面我们创建一个Button类来继承它,实现一下draw函数。
//-----Button.h----
#include "Clickable.h"
#include <graphics.h> // 引用图形库头文件
#include <conio.h>
class Button: public Clickable
{
public:
Button(int x, int y, int height, int width);
void draw() override;
};
//------Button.cpp----
#include "Button.h"
Button::Button(int x, int y, int height, int width)
{
this->x = x;
this->y = y;
this->height = height;
this->width = width;
}
void Button::draw()
{
fillrectangle(x, y,x + width, y + height);
}
可以看到, Button做的事情只是实现的draw函数画了个 矩形 没什么特殊的。下面最激动人心的时刻来了,我们在主函数里,把他画出来吧!!!
#include "Button.h"
using namespace std;
//bt点击事件
void bt_clickAction() {
setfillcolor(BLUE);
fillcircle(100, 300, 25);
}
//bt2点击事件
void bt2_clickAction() {
setfillcolor(RED);
fillcircle(400, 300, 25);
}
int main()
{
initgraph(640, 480);//初始化画布
//创建两个Button 对象
Button bt = Button(100, 100, 25, 60);
Button bt2 = Button(400, 100, 25, 60);
//为他们设置点击事件
bt.clickAction = bt_clickAction;
bt2.clickAction = bt2_clickAction;
//把他们绘制到屏幕上
bt.draw();
bt2.draw();
MOUSEMSG m; // 定义鼠标消息
while (true)
{
// 获取一条鼠标消息
m = GetMouseMsg();
switch (m.uMsg)
{
case WM_LBUTTONDOWN://按鼠标左键分发事件
bt.receiveEvent(m.x, m.y);
bt2.receiveEvent(m.x, m.y);
break;
case WM_RBUTTONUP:
return 0; // 按鼠标右键退出程序
}
}
// 关闭图形窗口
closegraph();
}
上面的代码注释很清楚了,也解决了我们开始的问题(if成灾的问题)可以看到在 WM_LBUTTONDOWN 这个分支里我一个 if 都没有。
来测试一下,
当我点击左边的按钮,
一个蓝色的⚪,横空出世. 当我点击右边的按钮,又是一个红色的⚪
别说代码反而变多了,20个按钮你试试?
写完了, 溜了溜了…