[wxWidget系列] wxWidget的事件机制
2011-04-20 09:11
155 查看
wxWidget
的事件机制
wxWidget
通过在编译期生成静态的事件表来实现事件类的事件处理。所有想要使用事件处理机制的地方都需要继承
wxEvtHandler
类(直接或间接)。
由于
window
控件需要处理自身的
UI
时间,故
wxWidget
将实现为
exEvtHandler
的基类,这就意味着所有的
wxWidget
的控件均是事件类,可以直接定义事件表。
a)
定义事件表的基本步骤:
1)
定义一个直接或间接继承自
wxEvtHandler
的类;
2)
定义所需的事件处理函数,函数格式:
void
Func(wx***Event& evt);
3)
在类的定义中使用
DECLARE_EVENT_TABLE()
声明事件表;
4)
在
cpp
文件中使用
BEGIN_EVENT_TABLE( SourcePanel, wxPanel )
和
END_EVENT_TABLE()
定义事件表。
5)
使用相应的事件宏在事件表中建立事件与处理函数的映射。
b)
窗口的事件查找流程:
当前窗口事件类
->1
级继承的事件类
->2
级继承事件类
->….->
父窗口事件类
…
上述的事件查找过程是建立在事件没有被处理的前提下。如果某个事件类处理了该事件,并没有调用
skip()
,那么该事件将被认为已经处理完毕,查找终止。
熟悉窗口的事件查找流程,对于有效处理事件极为关键。
使用者可以通过提前截获某事件,从而阻断后续的处理流程;使用者也可以提前截获事件,增加额外的事件处理逻辑
(
需调用
skip)
。
c) wxWindow
类的内部事件处理机制:
每个窗口类的内部均维护一个事件表栈,在事件传递给某个窗口类时,窗口类将事件逐一匹配事件表栈中事件表,也就是说最后放入的事件表将最先被匹配。用户可以通过
wxWindow::PushEvnetHandler
来压入事件表,通过
PopEventHandler
弹出事件表。一定要确保事件表中的事件处理对象的生存期大于窗口对象的生存期,除非
PopEventHandler
,并删除了该事件对象。记住:窗口本身也是一个事件处理对象,并作为第一个
EventHandler
被压入事件表栈。
wxWindow
的处理机制决定了使用者可以通过,改变事件表栈的顺序临时或永久的改变图形界面的行为。用户可以通过自定义的
wxEvtHandler
类,截获窗口事件,从而实现增加处理逻辑或过滤窗口事件的行为。
d)
下述事件不会传给事件源控件的父窗口,即当前窗口有效:
wxActivate, wxCloseEvent,
wxEraseEvent, wxFocusEvent, wxKeyEvent, wxIdleEvent, wxInitDialogEvent, wxJoystickEvent,
wxMenuEvent, wxMouseEvent, wxMoveEvent, wxPaintEvent, wxQueryLayoutInfoEvent, wxSizeEvent,
wxScrollWinEvent, wxSysColourChangedEvent
。
这么设计是因为这些控件仅对当前窗口有意义。当然这是
wxWidget
设计者的想法。在实际编程中,可能需要截获
wxMouseEvent
,
wxKeyEvent
等事件,并增加其他的处理逻辑,比如过滤相应的
key
事件等。有三种常见办法:
1)
重载窗口类,在新类中截获事件;
2)
重载
wxEvtHandler
,在新
Handler
中截获事件;见
wxWindow
类事件处理机制。
3)
使用动态的事件处理函数
Connect
。不常用,不介绍。
问题:如何在父窗口中截获子窗口的内部事件,如
wxMouseEvent
?
这个问题不难。根据上面的分析,
1)
重载窗口类并不现实,因为
wxMouseEvent
不会传给父窗口。
3)
动态事件处理机制可以实现,但是需要重载窗口类,重新
connect
事件与事件处理函数。
2)
重载
wxEvtHandler
,实现所需逻辑,并将该对象压入子窗口,从而达到事先截获子窗口事件的目的。个人感觉
2)
最为方便。
那么有个问题:可否直接将父窗口
Push
给子窗口呢?答案是:不行,虽然所有窗口均是
wxEvthandler
对象。为什么呢?因为所有的
wxWindow
对象对事件的处理都是极其复杂的,使用父窗口去拦截子窗口事件,会引起混乱,因为所有子窗口的事件都会首先传给父窗口。实践证实:将父窗口
Push
给子窗口会引发异常。
e)
窗口标识符
所有的
wxCommandEvent
均可以在多个窗口之间传递,如何实现特定窗口处理特定事件呢?
wxWidget
使用窗口标识符来标识窗口,从而在事件系统中实现定位特定窗口的作用。窗口标识符并不要求系统唯一,仅仅需要在特定的上下文中唯一即可。
窗口标识符仅仅是要使事件处理机制能够定位特定窗口,从而实现事件与窗口的映射。这意味着并不是所有的事件都关心窗口
ID
,尤其是那些不传递给父窗口的事件。
假设
wxWidget
的事件处理机制是完备的,那么通过事件宏,即可判断该事件是否会传递给父窗口:需要映射窗口
ID
的事件宏意味着该事件会传递给父窗口,反之,不然。
f)
事件对象的常用接口
1) skip()
是否继续传递该事件
(
继续处理
)
2)
传递参数:如
int
,
long
,
string
,
void*
等变量
3) wxNotifyEvent::veto()
使本次事件失效,相当于未发生
的事件机制
wxWidget
通过在编译期生成静态的事件表来实现事件类的事件处理。所有想要使用事件处理机制的地方都需要继承
wxEvtHandler
类(直接或间接)。
由于
window
控件需要处理自身的
UI
时间,故
wxWidget
将实现为
exEvtHandler
的基类,这就意味着所有的
wxWidget
的控件均是事件类,可以直接定义事件表。
a)
定义事件表的基本步骤:
1)
定义一个直接或间接继承自
wxEvtHandler
的类;
2)
定义所需的事件处理函数,函数格式:
void
Func(wx***Event& evt);
3)
在类的定义中使用
DECLARE_EVENT_TABLE()
声明事件表;
4)
在
cpp
文件中使用
BEGIN_EVENT_TABLE( SourcePanel, wxPanel )
和
END_EVENT_TABLE()
定义事件表。
5)
使用相应的事件宏在事件表中建立事件与处理函数的映射。
b)
窗口的事件查找流程:
当前窗口事件类
->1
级继承的事件类
->2
级继承事件类
->….->
父窗口事件类
…
上述的事件查找过程是建立在事件没有被处理的前提下。如果某个事件类处理了该事件,并没有调用
skip()
,那么该事件将被认为已经处理完毕,查找终止。
熟悉窗口的事件查找流程,对于有效处理事件极为关键。
使用者可以通过提前截获某事件,从而阻断后续的处理流程;使用者也可以提前截获事件,增加额外的事件处理逻辑
(
需调用
skip)
。
c) wxWindow
类的内部事件处理机制:
每个窗口类的内部均维护一个事件表栈,在事件传递给某个窗口类时,窗口类将事件逐一匹配事件表栈中事件表,也就是说最后放入的事件表将最先被匹配。用户可以通过
wxWindow::PushEvnetHandler
来压入事件表,通过
PopEventHandler
弹出事件表。一定要确保事件表中的事件处理对象的生存期大于窗口对象的生存期,除非
PopEventHandler
,并删除了该事件对象。记住:窗口本身也是一个事件处理对象,并作为第一个
EventHandler
被压入事件表栈。
wxWindow
的处理机制决定了使用者可以通过,改变事件表栈的顺序临时或永久的改变图形界面的行为。用户可以通过自定义的
wxEvtHandler
类,截获窗口事件,从而实现增加处理逻辑或过滤窗口事件的行为。
d)
下述事件不会传给事件源控件的父窗口,即当前窗口有效:
wxActivate, wxCloseEvent,
wxEraseEvent, wxFocusEvent, wxKeyEvent, wxIdleEvent, wxInitDialogEvent, wxJoystickEvent,
wxMenuEvent, wxMouseEvent, wxMoveEvent, wxPaintEvent, wxQueryLayoutInfoEvent, wxSizeEvent,
wxScrollWinEvent, wxSysColourChangedEvent
。
这么设计是因为这些控件仅对当前窗口有意义。当然这是
wxWidget
设计者的想法。在实际编程中,可能需要截获
wxMouseEvent
,
wxKeyEvent
等事件,并增加其他的处理逻辑,比如过滤相应的
key
事件等。有三种常见办法:
1)
重载窗口类,在新类中截获事件;
2)
重载
wxEvtHandler
,在新
Handler
中截获事件;见
wxWindow
类事件处理机制。
3)
使用动态的事件处理函数
Connect
。不常用,不介绍。
问题:如何在父窗口中截获子窗口的内部事件,如
wxMouseEvent
?
这个问题不难。根据上面的分析,
1)
重载窗口类并不现实,因为
wxMouseEvent
不会传给父窗口。
3)
动态事件处理机制可以实现,但是需要重载窗口类,重新
connect
事件与事件处理函数。
2)
重载
wxEvtHandler
,实现所需逻辑,并将该对象压入子窗口,从而达到事先截获子窗口事件的目的。个人感觉
2)
最为方便。
那么有个问题:可否直接将父窗口
Push
给子窗口呢?答案是:不行,虽然所有窗口均是
wxEvthandler
对象。为什么呢?因为所有的
wxWindow
对象对事件的处理都是极其复杂的,使用父窗口去拦截子窗口事件,会引起混乱,因为所有子窗口的事件都会首先传给父窗口。实践证实:将父窗口
Push
给子窗口会引发异常。
e)
窗口标识符
所有的
wxCommandEvent
均可以在多个窗口之间传递,如何实现特定窗口处理特定事件呢?
wxWidget
使用窗口标识符来标识窗口,从而在事件系统中实现定位特定窗口的作用。窗口标识符并不要求系统唯一,仅仅需要在特定的上下文中唯一即可。
窗口标识符仅仅是要使事件处理机制能够定位特定窗口,从而实现事件与窗口的映射。这意味着并不是所有的事件都关心窗口
ID
,尤其是那些不传递给父窗口的事件。
假设
wxWidget
的事件处理机制是完备的,那么通过事件宏,即可判断该事件是否会传递给父窗口:需要映射窗口
ID
的事件宏意味着该事件会传递给父窗口,反之,不然。
f)
事件对象的常用接口
1) skip()
是否继续传递该事件
(
继续处理
)
2)
传递参数:如
int
,
long
,
string
,
void*
等变量
3) wxNotifyEvent::veto()
使本次事件失效,相当于未发生
相关文章推荐
- [wxWidget系列] wxWidget的事件机制
- 事件机制-Spring 源码系列(4)
- 【深入浅出Node.js系列四】Node.js的事件机制
- Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制
- IOS开发系列——UIView专题之四:事件分发机制篇【整理,部分原创】
- 应付面试系列之事件分发机制
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制
- Android自定义控件系列九:从源码看Android触摸事件分发机制
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制
- iOS开发系列课程(02) --- 视图交互和事件机制
- android-----事件分发机制测试系列(二)
- C++综合系列之模拟事件机制
- Android自定义控件系列九:从源码看Android触摸事件分发机制
- 图片会说话系列之Android事件的分发传递机制
- android-----事件分发机制测试系列
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制
- Android自定义控件系列九:从源码看Android触摸事件分发机制
- WPF快速入门系列(3)——深入解析WPF事件机制
- wxWidget的事件机制