C++GUI之wxWidgets(9)-编写应用涉及的类和方法(4)-事件处理(3)

news2024/11/16 11:37:17

目录

    • 动态事件处理
    • 如何处理事件
    • 事件如何向上传播
    • 事件处理程序链

动态事件处理

void MyFrameHandler::OnFrameExit(wxCommandEvent&)
{
    // Do something useful.
}
 
MyFrameHandler myFrameHandler;
 
MyFrame::MyFrame()
{
      Bind(wxEVT_MENU, &MyFrameHandler::OnFrameExit,
              &myFrameHandler, wxID_EXIT);
}

注意,MyFrameHandler不需要从wxEvtHandler派生。但请记住,myFrameHandler的生存期必须大于MyFrame对象的生存期,或者至少需要在销毁之前解除绑定。

要使用普通函数或静态方法作为事件处理程序,可以编写如下内容:

void HandleExit(wxCommandEvent&)
{
    // Do something useful
}
 
MyFrame::MyFrame()
{
    Bind(wxEVT_MENU, &HandleExit, wxID_EXIT);
}

最后,您可以绑定到任意函子并将其用作事件处理程序:

struct MyFunctor
{
    void operator()(wxCommandEvent&)
    {
        // Do something useful
    }
};
 
MyFunctor myFunctor;
 
MyFrame::MyFrame()
{
    Bind(wxEVT_MENU, myFunctor, wxID_EXIT);
}

在C++11中,可以直接使用lambda表达式,而不必定义单独的函子类:

MyFrame::MyFrame()
{
    Bind(wxEVT_MENU,
         [](wxCommandEvent&) {
            // Do something useful
         },
         wxID_EXIT);
}

泛型函子的另一个常见示例是boost::function<>,或者,从C++11开始,std::function<>:

#if wxCHECK_CXX_STD(201103L)
using namespace std;
using namespace std::placeholders;
#else // Pre C++11 compiler
using namespace boost;
#endif
 
void MyHandler::OnExit(wxCommandEvent&)
{
    // Do something useful
}
 
MyHandler myHandler;
 
MyFrame::MyFrame()
{
    function<void (wxCommandEvent& )> exitHandler(bind(&MyHandler::OnExit, &myHandler, _1));
 
    Bind(wxEVT_MENU, exitHandler, wxID_EXIT);
}

借助bind<>(),甚至可以使用没有正确签名的方法或函数:

void MyHandler::OnExit(int exitCode, wxCommandEvent&, wxString goodByeMessage)
{
    // Do something useful
}
 
MyHandler myHandler;
 
MyFrame::MyFrame()
{
    function<void (wxCommandEvent&)> exitHandler(
            bind(&MyHandler::OnExit, &myHandler, EXIT_FAILURE, _1, "Bye"));
 
    Bind(wxEVT_MENU, exitHandler, wxID_EXIT);
}

总之,使用Bind<>()需要稍微更多的类型,但比使用静态事件表更灵活,因此在需要额外的功能时,不要犹豫使用它。另一方面,在不需要这种额外灵活性的简单情况下,事件表仍然非常好。

如何处理事件

当从窗口系统接收到事件时,wxWidgets将调用wxEvtHandler::ProcessEvent(),该对象属于生成事件的窗口。
ProcessEvent()搜索事件表的正常顺序如下,一旦找到处理程序,事件处理就会停止(除非处理程序调用wxEvent::Skip(),在这种情况下,它不算处理了事件,搜索会继续):

0.在发生任何其他事情之前,调用wxApp::FilterEvent()。如果它返回除-1以外的任何值(默认值),则事件处理将立即停止。
1.如果对象是wxWindow并具有关联的验证器,则wxValidator有机会处理该事件。
2.如果通过调用wxEvtHandler::SetEvtHandlerEnabled()禁用了此事件处理程序,则跳过接下来的两个步骤,并在步骤(5)继续执行事件处理程序。
3.查询动态绑定事件处理程序的列表,即调用Bind<>()的事件处理程序。请注意,这是在检查静态事件表条目之前完成的,因此,如果动态和静态事件处理程序都匹配同一事件,则除非在动态事件处理程序中调用wxEvent::Skip(),否则永远不会使用静态事件。还请注意,在程序运行时,动态绑定的处理程序按照其注册的相反顺序进行搜索,即,稍后绑定的处理比之前绑定的处理优先。」
4.检查包含使用该类及其基类中的事件表宏定义的所有处理程序的事件表。事件表中的搜索遵循源代码中事件宏出现的顺序,即较早出现的条目优先于较晚出现的条目。注意,这意味着在基类中定义的任何事件处理程序都将在这一步执行。
5.事件被传递到事件处理程序链中的下一个事件处理程序(如果有的话),即对其执行步骤(1)到(4)。
6.如果对象是wxWindow,并且事件被设置为传播(默认情况下,只有wxCommandEvent派生的事件被设置成传播),则处理从父窗口的步骤(1)(不包括步骤(7))重新开始。如果此对象不是窗口,但存在下一个处理程序,则如果它是窗口,则将事件传递给其父对象。这确保了在通常情况下(可能是几个)非窗口事件处理程序被推到窗口顶部时,事件最终到达窗口父级。
7.最后,即,如果事件仍然没有处理,wxApp对象本身(从wxEvtHandler派生)将获得最后一次处理它的机会。

请密切注意第6步!人们常常忽视或被wxWidgets事件处理系统的这一强大功能所迷惑。事件在窗口层次结构上传播。

此外,请注意,作为wxWidgets文档视图框架一部分的窗口的事件处理中还有其他步骤,即wxDocParentFrame、wxDocChildFrame及其MDI等价物wxDocMDIParentFrame和wxDocMDIChildFrame。

  1. 父框架类修改上面的步骤(2),将它们接收到的事件首先发送到wxDocManager对象。
  2. 然后,该对象将事件发送到当前视图,视图本身允许其关联文档首先处理该事件。
  3. 子框架类将事件直接发送到关联视图,该视图仍将其转发到其文档对象。

请注意,为了避免记住事件在文档视图框架中处理的确切顺序,最简单也是推荐的解决方案是仅在视图类级别处理事件,而不是在文档或文档管理器类中处理事件

事件如何向上传播

如上所述,从wxCommandEvent派生的类的事件如果没有在该窗口本身中处理,则默认情况下会传播到父窗口。但是,尽管默认情况下只有命令事件是这样传播的,但也可以传播其他事件,因为事件处理代码使用wxEvent::ShouldPropagate()来检查是否应该传播事件。也可以只传播有限次数的事件,直到它被处理(或到达顶级父窗口)。

最后,还有一个额外的复杂性(事实上,这大大简化了wxWidgets程序员的生活):当将命令事件传播到父窗口时,事件传播在到达父对话框时停止(如果有的话)。这意味着当弹出模式对话框时,您不会冒险从对话框控件中获取意外事件(对话框本身可能不会处理这些事件,因为它不关心这些事件)。然而,事件确实会传播到帧之外。这种选择的理由是,在一个典型的应用程序中只有几个框架,程序员很好地理解它们的父子关系,而如果不是不可能的话,可能很难追踪复杂程序中可能弹出的所有对话框(请记住,有些是由wxWidget自动创建的)。如果出于某种原因需要指定不同的行为,则可以显式使用wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS)来防止事件传播到给定窗口之外,或者在默认情况下为打开该标志的对话框取消设置该标志。

通常,将窗口作为窗口处理的事件(大小、运动、绘画、鼠标、键盘等)仅发送到窗口。具有更高级别含义或由窗口本身生成的事件(按钮单击、菜单选择、树展开等)是命令事件,并发送给父级,以查看其是否对事件感兴趣。更准确地说,如上所述,所有不是从wxCommandEvent派生的事件类(参见wxEvent继承映射)都不会向上传播。

在某些情况下,程序员可能希望在父窗口中获得一定数量的系统事件,例如,发送到对话框中的本地控件但未被其使用的所有关键事件。在这种情况下,必须编写一个特殊的事件处理程序,它将重写ProcessEvent(),以便将所有事件(或它们的任何选择)传递给父窗口。

事件处理程序链

事件传播算法的步骤5检查事件处理程序链中的下一个处理程序。此链可以使用wxEvtHandler::SetNextHandler()形成:
在这里插入图片描述
(参考图像,如果调用了A->ProcessEvent,但它不处理该事件,则将调用B->ProcessEvent等…)。

此外,在wxWindow的情况下,可以使用wxWindow::PushEventHandler()构建堆栈(使用wxEvtHandler双链接列表实现):
在这里插入图片描述
(参考图,如果调用了W->ProcessEvent,它将立即调用A->ProcessEvent;如果A或B都不处理该事件,则使用wxWindow本身——即,在测试所有推送的事件处理程序之后,wxWindow的动态绑定事件处理程序和静态事件表项被视为最后一种可能)。

默认情况下,链为空,即没有下一个处理程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java数组的定义与使用

Java数组的定义与使用 文章目录Java数组的定义与使用数组的基本概念什么是数组数组的创建数组的初始化数组的使用数组中元素访问遍历数组数组是引用类型初始JVM的内存分布基本类型变量与引用类型变量的区别引用变量几道例题认识null数组的应用场景保存数据作为函数的参数参数传…

TypeScript中的泛型

泛型&#xff08;Generics&#xff09;是指在定义函数、接口或类的时候&#xff0c;不预先指定具体的类型&#xff0c;而在使用的时候再指定类型的一种特性。 通常用T来指代任意输入的类型&#xff0c;除了T之外&#xff0c;以下是常见泛型变量代表的意思&#xff1a; K(Key…

信息安全技术 可信计算规范 可信平台控制模块 学习笔记(一)

声明 本文是学习信息安全技术 可信计算规范 可信平台控制模块. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 可信计算规范 缩略语 下列缩略语适用于本文件。 I/O&#xff1a;输入输出&#xff08;Input/Output&#xff09; IP&#xff1…

第三十八章 贪心算法——区间问题及证明(上)

第三十八章 贪心策略——区间相关问题一、什么贪心策略&#xff1f;二、区间问题合集1、思路&#xff1a;2、问题1&#xff1a; 区间选点&#xff08;1&#xff09;问题&#xff08;2&#xff09;思路和证明a.思路b.证明&#xff08;3&#xff09;代码3、问题2&#xff1a;&…

java:文件分片上传

代码下载地址&#xff1a;https://download.csdn.net/download/u013938578/87358484 1 文件上传、断点续传服务端 1.1 新建maven项目 文件结构如下&#xff1a; 1.2 引入百度开源上传组件webuploader 1.3 前端页面upload.html <!DOCTYPE html> <html lang"en&…

Java个人家乡博客源码

概述 个人博客相册家乡主题&#xff0c;用户注册后可以发布关于家乡的特色文章介绍&#xff0c;可以发布照片&#xff0c;相册管理&#xff0c;留言&#xff0c;评论&#xff0c;回复&#xff0c;收藏&#xff0c;关注 演示视频 https://www.bilibili.com/video/BV1iy4y1x7w6…

SSM框架-注解开发

11 注解开发 11.1 注解开发定义Bean 代码 接口BookDao public interface BookDao {void save(); }实现类BookDaoImpl【更改之处】 在最上面Component(“bookDao”) Component("bookDao") //或者Repository("bookDao") public class BookDaoImpl impl…

【C++】-- 哈希(上万字详细配图配代码从执行一步步讲解)

目录 哈希 常见哈希函数 除留余数法 哈希冲突 哈希冲突解决 闭散列 a、线性探测 插入 查找 删除 线性探测的实现代码 b、二次探测 二次探测的实现 开散列 开散列实现 插入 查找 删除 析构函数 代码汇总 哈希 常见哈希函数 直接定址法 -- (常用)-- 不存在哈…

2022 年博客总结

时间过的飞快&#xff0c;孩子也快4岁了&#xff0c;1号带孩子去玩雪&#xff0c;发生了一件有趣的事&#xff0c;发个视频。 带孩子玩雪我拉着闺女&#xff0c;闺女拉着儿子&#xff0c;忽略了力的作用&#xff0c;我以为只有我在使劲&#xff0c;实际上闺女需要需要更大的力拉…

java8新特性——函数式编程

文章目录1.函数式编程思想1.1概念1.2函数式编程的思想2.Lambda表达式2.1概述2.2核心原则2.3基本格式2.4Lambda表达式练习2.5省略规则3.Stream流3.1概述3.2案例准备3.3Steam流操作案例3.3.1需求3.3.2实现3.4Stream常用操作3.4.1创建stream流方式3.4.2中间操作3.4.2.1filter3.4.2…

SpringMVC 底层机制的简易实现

SpringMVC 底层机制的简易实现项目基础配置 xml 文件开发指南开发步骤1.初始化数据2.中央控制器 - 分发请求3.开发者角度4.视图解析器开发总结项目基础 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId&g…

【Python基础】常用数据结构及处理

1. KeyValue dict.clear() 删除字典内所有元素dict.copy()返回一个字典的浅复制[dict.fromkeys(seq, val])创建一个新字典&#xff0c;以序列 seq 中元素做字典的键&#xff0c;val 为字典所有键对应的初始值 dict.get(key, defaultNone) 返回指定键的值&#xff0c;如果值不在…

prompt模型详解之文本生成

prompt在生成方面的应用从两个方面进行介绍&#xff1a; 评估手段 具体任务 评估手段 生成任务的评估手段主要分为四种类型&#xff1a; 1). 基于N-gram匹配 2). 基于编辑距离 3). 基于词向量 4). 基于可学习方式。 本小节主要介绍BARTSCORE&#xff0c;其使用prompt方…

Python杂题

目录 一、前言 二、例题1——修剪灌木 三、例题2—— 付账问题 四、例题3——最少砝码 五、例题四——矩形拼接 六、例题五——蜂巢 一、前言 竞赛题有很多不需要什么算法的题目&#xff0c;只要学过编程语言就能做&#xff0c;其考核思维、逻辑、编码能力。而这种题有“…

【算法题解】 8. K 个一组翻转链表

文章目录题目解题思路代码实现复杂度分析题目 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持…

Python中编码(encode)解码(decode)讲解

嗨害大家好鸭&#xff01;我是小熊猫~ 这次也是给大家带来一点干货~ 所用素材:点击此处跳转文末名片获取 一、python3中str与unicode 在python3中&#xff0c;字符串有两种形式&#xff1a;str和bytes&#xff0c;两者区别如下&#xff1a; unicode string(str类型)&#xf…

【经验】关于区分cin、getline、cin.getline三种字符串输入的区别

cin 既可以输入char[]数组&#xff0c;也可以输入string类型&#xff0c;输入会被空格打断 cin对char进行输入 #include<bits/stdc.h> using namespace std; int main(){char ch[50];cin>>ch;cout<<strlen(ch)<<endl;for(int i0;i<strlen(ch);i){…

1.移动机器人发展现状

移动机器人主要应用场景&#xff1a; 场景1.仓储机器人(AGV自动导引运输车)&#xff1a;电商企业用户下单后机器人可以实现自动分拣和发货。需要多个传感器配合 2.自动驾驶领域(AMR自主移动机器人):车辆避让行人、导航等 热点研究领域&#xff1a; 环境感知和建模、人机交互…

2022简要总结和2023行动指南

在这辞旧迎接之际&#xff0c;心存感恩&#xff0c;放眼未来。 祝宝妈妈宝&#xff0c;幸福快乐&#xff1b; 祝国泰民安&#xff0c;政通人和。 祝百融云创系&#xff0c;生意兴隆&#xff1b; 祝公司老板们&#xff0c;大展宏图&#xff1b; 祝同事同行er&#xff0c;身…

Java算法_LeetCode:旋转数组

旋转数组 给你一个数组&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,…