【wxWidgets 教程】事件篇Ⅰ(三)

本文介绍了wxWidgets中的事件处理机制,包括事件的基本概念、注册方式(事件表、Bind和Connect)、触发顺序以及各种类型的事件绑定方法。同时,文中提供了多个示例来说明如何绑定成员函数、普通函数、lambda表达式和函数对象。此外,还讨论了事件表的使用和事件类型的定义。
摘要由CSDN通过智能技术生成

参考文档:https://docs.wxwidgets.org/3.2/overview_events.html

一、事件介绍

与其他GUI框架一样,wxWidgets 的控制流是基于事件控制的,即 wxWidgets 的操作大部分都是在事件里面执行的。
事件整体有两种,一种直接与用户操作挂钩的事件(例如鼠标、按钮事件),还有一种是不直接与用户操作对应的事件(例如定时器Socket事件)。

二、注册方式

  • 通过事件表进行事件的注册
  • 通过 Bind 函数进行事件绑定
  • 通过 Connect 进行事件绑定(它需要手动用 Disconnect 解绑事件)

三、触发顺序

同一线程下按照以下顺序(测试了几千次,包括触发频率极高的鼠标移动事件,目前没见到有特例):

  1. Bind 绑定的函数
  2. Connect 绑定的函数
  3. 事件表注册的函数

注意,如果一个事件同时被这三种方式绑定,如果在优先触发的函数中没有对事件执行 Skip() 函数,则会后面绑定的函数将会不起作用。例如,我使用 Bind 绑定了 fun1(),使用事件表注册了 fun2(),如果 fun1() 的事件对象没有执行 Skip(),则 fun2() 永远也不会被这个事件的事件表所触发。

四、事件类型

事件类型主要用于 BindConnect,在事件表并不适用。以下是示例:

Bind

MyFrame::MyFrame(...)
{
    Bind(wxEVT_MOTION, &MyFrame::onMotion, this);
}

void MyFrame::onMotion(wxMouseEvent &WXUNUSED(e))
{
	printf("函数被触发\n");
	fflush(stdout);
}

Connect

MyFrame::MyFrame(...)
{
    Connect(wxEVT_MOTION, (wxObjectEventFunction)&MyFrame::onMotion);
}

MyFrame::~MyFrame()
{
	Disconnect(wxEVT_MOTION, (wxObjectEventFunction)&MyFrame::onMotion);  // 这句别忘了
}

void MyFrame::onMotion(wxMouseEvent &WXUNUSED(e))
{
    wxPoint pos = e.GetPosition();  // 获取当前鼠标的坐标
	printf("鼠标在坐标 (%d,%d) 处\n", pos.x, pos.y);
	fflush(stdout);
}

上述两个例子中,wxEVT_MOTION 就是一个事件类型,它表示的是鼠标移动事件,如果把该事件绑定到一个函数中,那么当鼠标移动时就会调用该函数。

五、Bind的多种使用方式

1. 绑定成员函数

Bind(wxEVT_MOTION, &MyFrame::OnMotion, this);

2. 绑定普通函数

Bind(wxEVT_MOTION, OnMotion);

3. 绑定lambda

Bind(wxEVT_MOTION, []{ print("hello"); });

4. 绑定函数对象

std::function fun = [] { print("hello"); };
Bind(wxEVT_MOTION, []{ print("hello"); });
void OnMotion(wxMouseEvent &e)
{
    printf("hello\n");
    fflush(stdout);
    e.Skip();
}
...
// 某个成员函数内部...
std::function fun = OnMotion;
Bind(wxEVT_MOTION, fun);

5. 绑定 std::bind

void onMotion(wxMouseEvent &e, int i)
{
    printf("flag is %d", i);
    fflush(stdout);
    e.Skip();
}
...
// 某个成员函数内部...
int myFlag = 10;
Bind(wxEVT_MOTION, std::bind(onMotion2, std::placeholders::_1, myFlag));

以上列举的是常用的方法,可能还有其他的一些使用方式,但我目前没用上,有意者欢迎留言补充。

六、事件表的使用方式

事件表的写法与MFC有点相似。首先,要在类声明中添加这句代码:

wxDECLARE_EVENT_TABLE();

推荐添加到类声明的最后,这样可以避免搞乱作用域。
然后在类声明之后(我习惯放在源文件中)添加以下代码:

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
	// 此处注册事件
wxEND_EVENT_TABLE()

事件表便添加成功。现在,添加一个事件:

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
	EVT_SIZE(MyFrame::OnSize)
wxEND_EVENT_TABLE()

这个事件在窗口size改变时被触发。EVT_SIZE 宏是窗口size的事件宏,它只接受一个参数。当然有接受两个参数的事件宏,例如 EVT_MENU,它把菜单项与事件函数连接了起来,用法如下:

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
	EVT_MENU(ID_MENU_ABOUT, MyFrame::OnAbout)
wxEND_EVENT_TABLE()

至于事件宏能不能传入普通函数,我目前没成功过,想尝试的小伙伴可以试试~~


事件篇Ⅰ 至此完毕,欢迎大家指正!还请大家点点赞,给我点动力~~

上一篇:【wxWidgets 教程】HelloWorld 程序详细介绍(二)
下一篇:【wxWidgets 教程】事件篇Ⅱ(四)

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xiao_Ley

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值