【wxWidgets 教程】事件篇Ⅲ(五)

文章介绍了wxWidgets框架中如何使用wxApp::FilterEvent()函数拦截和处理事件,通过示例展示了如何重载该函数来响应按钮点击事件。同时,文章详细阐述了wxEvtHandler::ProcessEvent()在事件处理中的作用以及整个事件处理的顺序,包括TryBefore(),TryAfter()函数的作用,以及事件如何在事件处理链中传播。
摘要由CSDN通过智能技术生成

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

一、事件拦截(wxApp::FilterEvent())

wxApp::FilterEvent() 函数是wxWidgets中的一个可选重载函数,它允许您在事件到达目标对象之前对事件进行预处理。这个函数可以用来在事件分发之前修改事件,或者直接处理并阻止它进一步传播。
函数原型如下:

/**
 * @param event 要处理的事件对象的引用。可以是一个wxEvent的派生类,例如wxCommandEvent、wxMouseEvent等
 * @retval wxEventFilter::Event_Skip 继续处理事件,将事件传递给目标对象(默认实现返回的就是这个值)
 * @retval wxEventFilter::Event_Ignore 已经处理了事件,不需要进一步传递
 * @retval wxEventFilter::Event_Processed 停止处理事件,不要传递给目标对象
 */
virtual int wxAppConsole::FilterEvent(wxEvent &event);

要使用 wxAppConsole::FilterEvent(),你就需要在 wxAPP 中重载它,wxAPP 其实就是程序入口。废话少说,上才艺:

#include <wx/wx.h>

class MyFrame : public wxFrame
{
public:
    explicit MyFrame(const wxString &title)
      : wxFrame(nullptr, wxID_ANY, title, wxDefaultPosition, wxSize(400, 250))
    {
        new wxButton(this, wxID_ANY, "Click me!", wxDefaultPosition, wxDefaultSize); // 注意,这个按钮会占满整个窗口,原因我已经在之前的文章中有说
    }
};


class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        auto *frame = new MyFrame("FilterEvent Example");
        frame->Show(true);
        return true;
    }

    int FilterEvent(wxEvent &event) override
    {
        // 检查是否是按钮点击事件
        if (event.GetEventType() == wxEVT_BUTTON) {
            wxMessageBox("Button clicked!", "Information", wxOK | wxICON_INFORMATION);
            return wxEventFilter::Event_Ignore; // 表示事件已经处理,不需要进一步传递
        }

        return wxEventFilter::Event_Skip; // 对于其他事件,继续处理并传递给目标对象
    }
};

IMPLEMENT_APP(MyApp)

在这个示例中,我们重载了 MyApp 类的 FilterEvent() 函数,检查事件类型是否为 wxEVT_BUTTON。如果是按钮点击事件,我们显示一个消息框,并返回 wxEventFilter::Event_Ignore(也就是0),表示事件已经处理,不需要进一步传递。对于其他事件,我们返回 wxEventFilter::Event_Skip,让它们继续传递并被相应的处理器处理。有图有真相:
FilterEvent Exanple

二、事件处理流程

说到事件处理流程,就不得不说一下 wxEvtHandler::ProcessEvent() 函数。它就是事件处理的入口,甚至连上面所说的 FilterEvent() 函数也是在它内部被调用的,看图:
Breakpoint
很明显,FilterEvent() 函数是被 wxEvtHandler::ProcessEvent() 调用的。
其实官方也很明确说到,一般情况下我们不需要调用这个函数(它是个虚函数),除非我们在开发一个新功能(如新控件)并定义新的事件类型时,就可能需要调用它。

需要注意的是,我们通常不需要重写 ProcessEvent() 函数来自定义事件处理,重写 TryBefore()TryAfter() 函数通常就足够了。

事件处理的顺序如下:

  1. 调用 wxApp::FilterEvent()。如果返回值不是-1(默认,等同于 wxEventFilter::Event_Skip),则处理停止。
  2. 调用 TryBefore()(如果对象是wxWindow且有关联的验证器,将会在这一步被处理)。如果返回true,则函数退出。
  3. 如果对象被禁用(通过调用 wxEvtHandler::SetEvtHandlerEnabled()),则跳到第7步
  4. 搜索使用 Bind<>() 绑定的动态事件表。按照从最近绑定到最早绑定的顺序查找。如果找到处理程序,执行它并返回true。但是,如果处理程序使用了 wxEvent::Skip() 表示没有处理事件,则继续搜索。
  5. 搜索使用事件表宏绑定的静态事件表。按照源代码中事件表宏出现的顺序查找(就是我们代码中的先后顺序)。如果查找失败,尝试基类事件表,依此类推。如果找到处理程序,应用前一步的相同逻辑。
  6. 将搜索应用于整个事件处理链。链的长度通常为1。使用 wxEvtHandler::SetNextHandler() 可以构建这样的链。如果链中的任何处理器返回true,函数将退出。
  7. 调用 TryAfter()。对于 wxWindow 对象,这可能会将事件传播(默认仅 wxCommandEvent 派生的事件传播)到窗口的父级(递归,又从第2步开始)。
  8. 如果事件仍未处理,将调用 wxTheApp(指向单例 wxApp 对象的全局指针)对象上的 ProcessEvent() 作为最后一步。

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

上一篇:【wxWidgets 教程】事件篇Ⅱ(四)
下一篇:【wxWidgets 教程】事件篇Ⅳ(六)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Xiao_Ley

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

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

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

打赏作者

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

抵扣说明:

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

余额充值