wxwidgets事件处理

Event

严谨来说,wxwidgets中每个事件都可以被以下三个事件描述:

1.事件类型  

它是一个唯一标识事件类型的东西,当然是宏定义的形式,例如#define wxEVT_COMMAND_BUTTON_CLICKED          wxEVT_BUTTON它标识按键点击这个事件类型

2.事件所携带的事件类  

每个事件都会有与之相关的信息,这些数据的传递是通过那些从wxevent派生的类实现的,而不同类型的事件可以使用相同的事件类,比如按button和选择listbox都使用wxcommandevent类(所有的control events都是用它)。但是键盘事件使用wxkeyevent,因为它们携带的信息不同。

3.事件源 

wxevent(事件所携带的事件类)保存了产生事件的东西,对窗口来说,就是他的标识id,而很多时候会有许多object产生相同种类的事件(比如一个窗口有好几个按键, 它们都产生相同的按键点击事件),检查事件源或id来分辨它们。


                                                                              event

Event Handling


               evenhanding

上面说了事件,下面谈谈事件处理。每一个wxEvtHandler的派生类(所有继承自wxwindows的窗口类及应用程序类都是wxEvtHandler的派生类),例如frame,按钮,菜单等都在内部维护一个事件表(这里指静态事件表与动态绑定),通过这个表将事件与事件处理函数关联在一起。

在wxwi中有两种主要的处理事件的方法,即事件表宏和动态绑定。事件表将在编译期间将事件与其处理函数静态的关联,而动态绑定发生在运行期间,而且还可以解除绑定。动态绑定可以直接将事件和以下处理绑定:1.别的object的处理2.普通函数3.一些库函数,像boost::function<>和std::function<>。

事件表:

创建一个静态事件表可能需要以下步骤:
1.定义一个直接或间接继承自wxEvtHandler的类
例如从wxFrame派生一个MyFrame,然后创建一个实例myframe。这个类将负责维护事件表,捕捉传递事件类。
2.在第一步创建的类中使用wxDECLARE_EVENT_TABLE()声明一个事件表。

3.为每一个你想处理的事件定义一个事件处理函数。

例如:

MyFrame::OnButton1(wxCommandEvent& event)
{.../*处理*/}


4.在cpp文件中使用wxBEGIN_EVENT_TABLE和wxEND_EVENT_TABLE()实现一个事件表,在其中增加事件宏,它将把事件与其处理函数关联起来。

例如:

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_BUTTON(BUTTON1, MyFrame::OnButton1)
wxEND_EVENT_TABLE()


其中onbutton1就是事件处理函数。而第一个参数button1就是上面说的事件源。evt_button是预设事件宏。而第三步中MyFrame::OnButton1函数参数就是一个事件类的引用。
假设你要实现按button1来显示一个helloworld信息,步骤可能是这样的:1.点击按键,产生按键点击事件(最前面说的事件类)。2.myframe窗口捕捉到这个事件,先查询在wxbutton中是否有符合条件的处理(如果找不到会到其基类的事件表查找,再找不到会到窗口控件的父子继承树中查找,比如这里正在说的在myframe中找到了),通过myframe中事件表得知对于标识符为button1(前面说的事件源)的按键事件应该发送到onbutton1函数,所以把携带事件信息的事件类传递给这个函数,后面就是处理函数处理过程,即弹出对话框显示helloworld。
那么最前面说的事件类型在哪里会被用到呢?其实点击按键时产生的事件类wxCommandEvent包含标识符button1和事件类型wxEVT_COMMAND_BUTTON_CLICKED,这两样结合起来在各个事件表中查找是否有对应处理。
注意:只有Command事件(指的是直接或间接继承自wxCommandEvent的事件)才会被递归的应用到其父窗口的事件表。因为非command事件只对产生它的窗口有意义。例如把一个子窗口的重绘事件发给它的父窗口就没有意义。

不会传递给其父窗口的事件表处理的事件如下:
wxActivate,wxCloseEvent,wxEraseEvent,wxFocusEvent,wxKeyEvent,wxIdleEvent,wxInitDialogEvent,wxJoystickEvent,wxMenuEvent,wxMouseEvent,wxMoveEvent,
wxPaintEvent,wxQueryLayoutInfoEvent,wxSizeEvent,wxScrollWinEvent,wxSysColourChangedEvent

动态绑定:

你可以这样实现动态绑定:

MyFrame::MyFrame(...)
{
      Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnButton1, this, BUTTON1);
}
Bind定义:

void wxEvtHandler::Bind
(
const EventTag & 
eventType,
void(Class::*)(EventArg &) 
method,
EventHandler * 
handler,
int 
id = wxID_ANY,
int 
lastId = wxID_ANY,
wxObject * 
userData = NULL
 
)
[inline]
Parameters:
eventType 
事件类型如:wxEVT_CHAR 是wxEventTypeTag模板类的一个实例.
method 
事件处理函数.
handler 
 事件处理函数的所属类的实例指针
id 
 变换事件处理控件的资源id(起始值)
lastId 
变换事件处理控件的资源id(结束值)由id和lastid确定了一个范围 
userData 
同事件相关的数据类, 

动态与静态事件表不同如下:

1.事件处理程序可以随时被绑定。例如,它可以先做一些初始化,然后在可以和处理程序绑定成功时绑定它。这可以避免你通过处理函数测试对象是否被正确地初始化。使用动态绑定他们不会被调用如果没有正确初始化。
2.动态绑定也可以随时被解绑,当然静态事件表也可以办到,但是动态只需少量代码,而且更清晰。
3.前面说的动态可以绑定的三种处理,这个对静态事件表来说是不可能的,因为它不能指定要发送事件类的处理函数。举个简单例子,如何接收一个frame的自己的frame children的鼠标移动事件。
前面说过,不是command事件,不会递归到父窗口事件表,而鼠标事件就不是command事件。所以在frame里定义事件表是行不通的。另一个方法是把事件表放在子窗口类里EVT_LEAVE_WINDOW(MyFrame::OnMouseLeave)。而调用MyFrame::OnMouseLeave只能使用子窗口指针来实现了,如childframe->OnMouseLeave,但是用子窗口指针而不是指向frame的指针去调用frame的方法将会是灾难性的(不使用子窗口指针无法把事件 类传过去,即携带事件信息的类。)。
但是使用动态绑定可以办到:

MyFrame::MyFrame(...)
{
  m_child->Bind(wxEVT_LEAVE_WINDOW, &MyFrame::OnMouseLeave, this);
}


当同时存在静态与动态处理对于同一事件,静态将会被执行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值