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

参考文档: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 教程】事件篇Ⅱ(四)

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
wxWidgets教程是一系列文章或资源,旨在帮助读者了解和学习如何使用wxWidgets构建跨平台的GUI应用程序。这些教程可以包括基本知识、准备工作、创建第一个wxWidgets程序、控件的使用以及其他相关主题。通过阅读这些教程,读者可以逐步了解和掌握wxWidgets的功能和用法。一些常见的wxWidgets教程资源包括官方文档、书籍和在线教程。在官方文档中,您可以找到关于wxWidgets的详细说明和使用指南。而书籍则提供了更深入的介绍和实例,帮助读者更好地理解和应用wxWidgets。此外,还有一些在线教程和博客文章,提供了一些实用的技巧和经验分享。引用<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [wxWidgets完整教程专栏完整目录 cpp](https://blog.csdn.net/update7/article/details/130023533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [wxWidgets教程(中文)](https://download.csdn.net/download/sweetbo/4871081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Xiao_Ley

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

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

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

打赏作者

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

抵扣说明:

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

余额充值