自定义事件

大体方法

就像每个事件被其事件类型所唯一确定一样,定义一个自定义事件从为它定义一个新事件类型开始。这通过使用wxDEFINE_EVENT()宏来完成。就像事件类型是可变的,如果有必要它也可以通过使用wxDECLARE_EVENT()宏来声明。

另一件要做的事情就是决定你是否需要为事件定义一个自定义事件类或使用已经存在的类,代表性的有wxEvent(它不会提供任何额外的信息)或wxCommandEvent(它包含几种额外的域,并且默认把事件向上传递)。这两种方式的细节都将都将在下面描述。代码详细说明和使用自定义事件类型的完整例子也可以在事件示例中查看。

最后你将需要产生并发送你的自定义事件。产生事件就像实例化你的自定义事件类并初始化其内部值那样简单。为了发送事件到一个特定的事件句柄,这里有两种可选:使用wxEvtHandler::AddPendingEventwxEvtHandler::QueueEvent当进行内部线程通信时,你基本上只需要使用后者。当你只使用主线程时,你也可以安全的使用前者。

最后需要注意的是,还有两个简单的全局封装函数关联到提到的那两个wxEvtHandler函数,即wxPostEvent()wxQueueEvent()

使用存在的事件类

如果你仅打算使用wxCommandEvent和一个新事件类型,可以使用下面列出的事件表宏之一而不用自己定义一个新事件类。

Example:

wxDECLARE_EVENT(MY_EVENT, wxCommandEvent);//这句很明显应该位于头文件中:它仅仅声明了MY_EVENT这个事件类型wxDEFINE_EVENT(MY_EVENT, wxCommandEvent);//这是事件类型定义,所以不能位于头文件wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)//用事件表处理事件的示例代码
EVT_MENU (wxID_EXIT, MyFrame::OnExit)
...
EVT_COMMAND (ID_MY_WINDOW, MY_EVENT, MyFrame::OnMyEvent)
wxEND_EVENT_TABLE()
void MyFrame::OnMyEvent(wxCommandEvent& event)//事件处理函数
{
// do something
wxString text = event.GetString();
}MyFrame::MyFrame()// 使用Bind<>()处理事件的示例代码:
{
Bind(MY_EVENT, &MyFrame::OnMyEvent, this, ID_MY_WINDOW);
}void MyWindow::SendEvent()// 产生事件的示例代码
{
wxCommandEvent event(MY_EVENT, GetId());
event.SetEventObject(this);
event.SetString("Hello");// 给它一些包含的信息
ProcessWindowEvent(event);//发送它
}

实验图:

定义你自己的事件类

在一些环境下,你必须定义你自己的事件类,例如从一个地方发送一些很复杂的数据到另一个地方。除了定义你的事件类,如果你打算事件表来处理这种类型的事件,你还需要定义你自己的事件表宏。

Here is anexample:

class MyPlotEvent: public wxEvent// 定义新事件类
{
public:
MyPlotEvent(wxEventType eventType, int winid, const wxPoint& pos)
: wxEvent(winid, eventType),
m_pos(pos)
{
}
wxPoint GetPoint() const { return m_pos; }// 获取成员变量
virtual wxEvent *Clone() const { return new MyPlotEvent(*this); }//实现纯虚函数
private:
const wxPoint m_pos;
};//我们定义了一个关联到上面的类的单独的事件类型 MY_PLOT_CLICKED ,但很明显你需要不止一个事件类型,例如,
//你还可以拥有MY_PLOT_ZOOMED或MY_PLOT_PANNED,在这种情况下你只需要在这添加更多相似的内容。
wxDEFINE_EVENT(MY_PLOT_CLICKED, MyPlotEvent);/**************************************************************************************************/
// 如果你想支持旧编译器你需要使用下面这些繁琐的宏:
typedef void (wxEvtHandler::*MyPlotEventFunction)(MyPlotEvent&);
#define MyPlotEventHandler(func) wxEVENT_HANDLER_CAST(MyPlotEventFunction, func)//如果你的代码使用现在流行的编译器编译,你就可以这样做:
#define MyPlotEventHandler(func) (&func)//最后定义一个宏为新的事件类型创建一个完整的事件表
//记住如果你使用Bind<>() 你就完全不需要这些,你可以仅使用 &func来代替MyPlotEventHandler(func),除非你用的是非常老的编译器。#define MY_EVT_PLOT_CLICK(id, func)  \
wx__DECLARE_EVT1(MY_PLOT_CLICKED, id, MyPlotEventHandler(func))//处理事件的示例代码(你将使用两者之一,而不是两个都用)
事件表:
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_PLOT(ID_MY_WINDOW, MyFrame::OnPlot)
wxEND_EVENT_TABLE()动态绑定:
MyFrame::MyFrame()
{
Bind(MY_PLOT_CLICKED, &MyFrame::OnPlot, this, ID_MY_WINDOW);
}void MyFrame::OnPlot(MyPlotEvent& event)
{
... do something with event.GetPoint() ...
}// 产生事件的示例代码:
void MyWindow::SendEvent()
{
MyPlotEvent event(MY_PLOT_CLICKED, GetId(), wxPoint(...));
event.SetEventObject(this);
ProcessWindowEvent(event);
}

实验图如下:

需要注意的是这句:

#define MY_EVT_PLOT_CLICK(id, func)  \
wx__DECLARE_EVT1(MY_PLOT_CLICKED, id, MyPlotEventHandler(func))

\是继续符,代表下一行接本行,我本来以为上面那个是说明文档里出错了,实际上是我错了。。还有里面有两个_接起来,我本来以为怎么可能起这种宏名,没想到真的是两个。。还有一个就是标识id是窗口id,我原来理解不到位,把触发事件的按钮的id当多了标识id,结果事件找不到对应的处理函数了。。。。

再一个,这句:

#define MyPlotEventHandler(func) (&func)

不知道干嘛用的,我不用这句,使用事件表依旧工作正常。。。

事件表的向上传递寻找之类的我现在也没怎么搞清楚,我从一个线程传递事件到非父窗口的窗口时大概如下:

自定义事件类:

class MyThreadEvent: public wxThreadEvent
{
public:MyThreadEvent(wxEventType eventType, int winid,unsigned char* pdate);virtual wxEvent *Clone() const {return new MyThreadEvent(*this);}unsigned char* GetPointer() const {return p;};
private:unsigned char* p;
};

事件类型也定义声明Ok:

头文件中:

wxDECLARE_EVENT(WX_POINTER_ARR,MyThreadEvent);

cpp中:

wxDEFINE_EVENT(WX_POINTER_ARR,MyThreadEvent);

然后写好事件映射宏:

#define EVT_POINTER_ARR(id,fn) DECLARE_EVENT_TABLE_ENTRY(WX_POINTER_ARR\,id\,-1\,&fn\,(wxObject*)NULL\),

注意最后的逗号不要丢,而\是继续符。

事件表:

BEGIN_EVENT_TABLE(showpic,wxFrame)EVT_POINTER_ARR(wxID_ANY,showpic::OnProcessThreadEvent)
END_EVENT_TABLE()

事件处理函数

void showpic::OnProcessThreadEvent(MyThreadEvent& event)
{image.Destroy();//清除原来的图片image=wxImage(col,row,event.GetPointer());//生成新的图片bitmap = wxBitmap(image.Scale(800,600));//调整大小Refresh(false);
}

最后是产生事件:

wxQueueEvent(windows,new MyThreadEvent(WX_POINTER_ARR,wxID_ANY,imgdate));

其中windows是处理事件的窗口的指针。

关于事件的产生

定义好事件类后,有下面几个函数可选:(下面是机翻的,哈哈)
virtual void wxEvtHandler :: QueueEvent wxEvent *  事件  
虚拟

事件放入队列以便进行后续处理。

该方法类似于ProcessEvent(),但是后者是同步的,即事件在函数返回之前立即被处理,这一个是异步的,并且将在稍后的时间(通常在下一个事件期间)处理事件循环迭代)。

另一个重要的区别是这个方法会获取事件参数的所有权,即它会自动删除它。这意味着事件应该在堆上分配,并且在函数返回之后指针不能再被使用(因为它可以随时被删除)。

QueueEvent()可用于从工作线程到主线程的线程间通信,它在内部使用锁定,并通过确保正在调用的线程不会再使用事件对象来避免AddPendingEvent()文档中提到的问题。应该注意避免该对象的某些字段被它使用,特别是事件对象的任何wxString成员不能是另一个wxString对象的浅层副本,因为这将导致它们在后台仍然使用相同的字符串缓冲区。例如:

void FunctionInAWorkerThread(constwxString&str)
{
wxCommandEvent * evt =new wxCommandEvent ;
// NOT evt-> SetString(str),因为这将是一个浅的副本
EVT-> 的SetString(STR。c_str());//做一个深层次的副本
wxTheApp - >QueueEvent(evt);
}

请注意,您可以使用wxThreadEvent而不是wxCommandEvent来避免此问题:

void FunctionInAWorkerThread(constwxString&str)
{
wxThreadEvent evt;
EVT。SetString(str);
// wxThreadEvent :: Clone()确保内部的wxString
//其他wxString实例不共享成员:
wxTheApp - >QueueEvent(EVT。克隆());
}

最后注意到,如果通过调用wxWakeUpIdle()当前处于空闲状态,则此方法会自动唤醒事件循环,因此在使用它时不需要手动执行。

以来
2.9.0
参数
事件 要排队的堆分配事件,QueueEvent()拥有它的所有权。该参数不应该NULL

在wxWindow中重新实现。

virtual void wxEvtHandler :: AddPendingEvent const wxEvent&  事件  
虚拟

发布事件稍后处理。

这个功能类似于QueueEvent() ,但不能用于发布来自工作线程事件与事件对象wxString场(即在实践中大多数),因为不安全使用相同的wxString对象,是因为该wxString原始事件对象中的字段及其由该函数内部创建的副本在内部共享相同的字符串缓冲区。使用QueueEvent()来避免这种情况。

一个事件副本由函数进行,所以一旦函数返回(原来是在堆栈上创建的),原来的代码就可以被删除。这要求wxEvent :: Clone()方法由事件实现,以便可以将其复制并存储直到被处理。

参数
事件 事件添加到挂起的事件队列。

在wxWindow中重新实现。

virtual bool wxEvtHandler :: ProcessEvent wxEvent&  事件  
虚拟

处理事件,搜索事件表并调用零个或多个合适的事件处理函数。

通常,您的应用程序不会调用此函数:它在wxWidgets实现中调用,以将传入的用户界面事件分派到框架(和应用程序)。

但是,如果实现定义新事件类型的新功能(例如新控件),则可能需要调用它,而不是允许用户覆盖虚拟函数。

请注意,您通常不需要重写ProcessEvent()来自定义事件处理,覆盖特别提供的TryBefore()和TryAfter()函数通常就足够了。例如,wxMDIParentFrame可以覆盖TryBefore(),以确保在父框架本身处理之前在活动子帧中处理菜单事件。

事件表搜索的正常顺序如下:

  1. wxApp :: FilterEvent()被调用。如果它返回任何东西-1(默认),处理在这里停止。
  2. TryBefore()被调用(这是wxWalidator被考虑在wxWindow对象的地方)。如果返回true,则退出该函数。
  3. 如果对象被禁用(通过调用wxEvtHandler :: SetEvtHandlerEnabled),该函数跳到步骤(7)。
  4. 使用Bind <>()绑定的处理程序的动态事件表在最近期绑定到最早绑定的顺序中进行搜索。如果找到一个处理程序,它将被执行,并且该函数返回true,除非使用wxEvent :: Skip()处理程序来表示它没有处理事件,在这种情况下搜索继续。
  5. 使用事件表宏绑定的处理程序的静态事件表按源代码中事件表宏的出现顺序搜索该事件处理程序。如果失败,则会尝试使用基类事件表,直到不再存在表或找到适当的函数为止。如果找到一个处理程序,则与上一步相同的逻辑适用。
  6. 搜索被应用在整个事件处理程序链上(通常链的长度为1)。这个链可以使用wxEvtHandler :: SetNextHandler()形成:(指图像,如果A->ProcessEvent被调用,并且不处理事件,B->ProcessEvent将被调用等等)。请注意,在wxWindow的情况下,您可以构建一堆事件处理程序(有关更多信息,请参阅wxWindow :: PushEventHandler())。如果任何链接的处理程序返回true,则该函数退出。
  7. TryAfter()被调用:对于wxWindow对象,这可能会将事件传播到窗口父(递归)。如果仍未处理该事件,则将wxTheApp对象上的ProcessEvent()作为最后一步进行调用。

注意步骤(2) - (6)在该函数调用的ProcessEventLocally()中执行。

参数
事件 事件处理。
返回
如果发现并执行了一个合适的事件处理函数,则该值为true,该函数未调用wxEvent :: Skip。
也可以看看
SearchEventTable()

在wxWindow中重新实现。

还有这两个,它们是全局函数:

void wxQueueEvent wxEvtHandler *  dest,
    wxEvent *  事件 
     

对给定对象进行处理排队事件。

这是围绕wxEvtHandler :: QueueEvent()的包装器,有关更多详细信息,请参阅其文档。

包含文件:

#include <wx / event.h> 
参数
DEST 对象将事件排队,不能NULL
事件 堆分配和非NULL事件队列,该函数拥有它的所有权。
void wxPostEvent wxEvtHandler *  dest,
    const wxEvent&  事件 
     

在GUI应用程序中,此函数使用wxEvtHandler :: AddPendingEvent()将事件发布到指定的dest对象。

否则,它使用wxEvtHandler :: ProcessEvent()立即调度事件。有关详细信息,请参阅各自的文档(和警告)。由于限制wxEvtHandler :: AddPendingEvent()这个函数是不是线程安全具有事件对象wxString字段,使用wxQueueEvent()来代替。

包含文件:

#include <wx / event.h>

按需调用

wxwidgets自定义事件+调试相关推荐

  1. wxWidgets:事件和事件处理

    wxWidgets:事件和事件处理 wxWidgets:事件和事件处理 事件处理 事件表的事件处理 动态事件处理 如何处理事件 事件如何向上传播 事件处理器链 自定义事件摘要 一般的做法 使用现有的事 ...

  2. 四、Vue组件化开发学习笔记——父子组件通信,父级向子级传值(props),子级向父级传值(自定义事件),slot插槽

    一.父子组件的通信 在上一篇博文中,我们提到了子组件是不能引用父组件或者Vue实例的数据的. 但是,在开发中,往往一些数据确实需要从上层传递到下层: 比如在一个页面中,我们从服务器请求到了很多的数据. ...

  3. vba 定义类_工作表中如何响应自定义事件

    大家好,在上两讲中讲了类模块的调试行为,对于我们写代码人员来讲,要充分地理解每个知识点的概念,才能在实际工作中灵活运用,在我的第一套教程<VBA代码解决方案>中,我推出的是一种积木编程的思 ...

  4. Android 友盟的计数功能,友盟统计_U-App应用统计之自定义事件统计

    自定义事件可以实现在应用程序中埋点来统计用户的点击行为.自定义事件目前包括"计数事件"和"计算事件",二者的区别以及详细说明请点击这里(http://dev.u ...

  5. uniapp 小程序接入友盟 ,自定义事件携带参数

    1.下载友盟的包 npm install umtrack-wx --save 2.配置 在根目录新建 track.js 和uma.js 文件 track.js 文件 /*** 全局事件统计,* 通过重 ...

  6. Vue组件绑定自定义事件

    Vue组件使用v-on绑定自定义事件: 可以分为3步理解: 1.在组件模板中按照正常事件机制绑定事件: template: '<button v-on:click="increment ...

  7. cocos2d-js 自定义事件监听派发

    熟悉js的dom事件或者flash事件的,基本都能立马明白cc.eventManager的用法. cc.eventManager有两种注册监听器的方式,一种是原生事件,例如 cc.eventManag ...

  8. Javascript框架的自定义事件(转)

    很多 javascript 框架都提供了自定义事件(custom events),例如 jquery.yui 以及 dojo 都支持"document ready"事件.而部分自定 ...

  9. cocos2d JS 自定义事件分发器(接收与传递数据) eventManager

    简而言之,它不是由系统自动触发,而是人为的干涉 较多情况用于传递数据 var _listener1 = cc.EventListener.create({event: cc.EventListener ...

  10. 如何订阅Form的自定义事件

    Window Form类有很多的属性/方法和事件,其中事件属于一种发布订阅模式 .订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主体对象.这个主体对象在自身状态变化时,会通知所 ...

最新文章

  1. 数据中心网络架构 — 云数据中心网络 — 大二层网络技术
  2. 查看tensorflow pb模型文件的节点信息
  3. 趣链 BitXHub跨链平台 (6)IBC通信协议
  4. Oracle使用goldengate分别向Oracle和mysql双路的单向复制
  5. 小白兔想的飞鸽传书(173dmba)安卓版
  6. 2019中国民营企业500强发布:华为、海航、苏宁位列前三
  7. html中滤镜的效果图,CSS滤镜之Mask属性-网页设计,HTML/CSS
  8. day8--pandas
  9. Windows 系统常用工具软件
  10. 北京专业一般人小规模代理记账
  11. 如何统计网页的浏览量?Steins
  12. php 自动生成考卷下载,试卷生成器下载-试卷生成器电脑版下载[试题生成]-华军软件园...
  13. xp如何快速升级win10系统
  14. css中的counter计数器
  15. 设计模式---外观(Facade)模式
  16. 2021-11-07 c语言之不变初心数
  17. 按哪个键进入BIOS设置
  18. iVMS-4200 Vs区别_76840红单足球预测 法甲 21:00 安格斯 VS 梅斯
  19. mysql 从多个表中删除行,MySQL从多个表中删除行
  20. 2000-XP-2003操作系统常见问题

热门文章

  1. 优雅的避免字体侵权——微软雅黑并不免费
  2. 程序员怎样出版一本技术书
  3. 【论文阅读】Generalization in Reinforcement Learning
  4. XCTF练习题---MISC---Cephalopod
  5. oracle根据身份证号码 计算年龄、性别
  6. MySQL 常用命令汇总
  7. box-shadow 详解
  8. 软件开发阶段及其文档简述
  9. 三种计算机控制系统是,计算机控制系统3
  10. 利用C51单片机内部函数_corl_函数实现LED流水灯。