Ubuntu下的wxWidgets事件驱动
1事件驱动编程
所有的GUI程序都是事件驱动的。也就是说,应用程序一直停留在一个循环中,等待来自用户或其它地方的事件,一旦接收到某个事件,就将它交给某个事件函数进行处理。虽然看上去不同的窗口是同时被刷新的,但实际上,绝大多数的GUI程序都是单线程的,因此窗口的刷新是按顺寻进行的。
WxWidgets事件由三部分来描述:
1 Event Type:标示事件类型(wxEventType)的唯一值。
2 Event Class:它是一个wxEvent的派生类。该类对象附带了事件的相关信息。
3 Event Source:wxEvent存储了产生事件的对象和它的标示符。这是事件系统中唯一确定事件产生源(窗口)的整数。不同的窗体可能会产生相同类型的事件,通过窗口标示符可以对它们加以区分。
2 事件表和事件处理过程
wxWidgets事件处理系统比起通常的虚方法机制说要稍微复杂一些,但它的一个好处是可以避免实现基类中所有的虚方法,因为实现所有的虚方法有时候是不切实际或者是低效率的。
每一个wxEvtHandler的派生类,例如Frame,按钮,菜单等,都会在其内部维护一个事件表,用来告诉wxWidgets事件和事件处理过程的对应关系。所有继承自wxWindows的窗口类以及应用程序都是wxEvtHandler的派生类。
3 动态事件表的加载
静态事件表是我们处理事件最常用也是比较简单的方式。但有的时候我们希望在程序运行的不同时间使用不同的映射关系,或者你更喜欢使用可以精确控制的事件,甚至是你希望在不同的类之间共享事件函数,这就需要动态事件映射的方法。
①voidwxEvtHandler::Connect (int id,
int last id,
wxEventType eventType,
wxObjectEventFunction function,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL)
Connects the given function dynamically with the event handler, id andevent type.
②voidwxEvtHandler::Connect (int id,
wxEventType eventType,
wxObjectEventFunction function,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL)
This overload can be used to attach an event handler to a single source ID.
③voidwxEvtHandler::Connect (int id, wxObjectEventFunction function,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL)
This overload will connect the given event handler so that regardless ofthe ID of the event source, the handler will be called.
③Disconnect (wxEventType eventType, wxObjectEventFunction function,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL);
②Disconnect (int id=wxID_ANY,
wxEventType eventType=wxEVT_NULL, wxObjectEventFunction function=NULL,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL);
①Disconnect (int id, intlastId,
wxEventType eventType, wxObjectEventFunction function=NULL,
wxObject *userData=NULL,
wxEvtHandler *eventSink=NULL);
Bind (constEventTag &eventType, Functorfunctor,
int id=wxID_ANY,
intlastId=wxID_ANY,
wxObject *userData=NULL)
该函数在功能上和Connect函数相同,但是它用任意函数处理事件,而Connect函数只能够使用wxEvtHandler的派生类函数。
4 自定义事件
每一个事件都是由事件类型(wxEventType)唯一确定的,所以在自定义事件的时候,首先应该定义一个新的事件类型。
wxDEFINE_EVENT()
wxDECLARE_EVENT()
然后确定我们要使用的是已经存在的事件类定义还是定义全新事件。
最后是产生事件和传递事件。所谓产生事件就是实例化事件类,即声明一个事件类对象并初始化。而传递消息就是处理消息的过程。
4.1使用已经存在的事件类
wxDECLARE_EVENT(name,cls)
//cls是一个已存在的wxEvent(派生)类。
定义静态事件表
事件处理
// this is typically in a header: it just declares MY_EVENT event type
wxDECLARE_EVENT(MY_EVENT,wxCommandEvent);
// this is a definition so can't be in a header
wxDEFINE_EVENT(MY_EVENT,wxCommandEvent);
// example of code handling the event with event tables
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
}
// example of code handling the event with Bind<>():
MyFrame::MyFrame()
{
Bind(MY_EVENT, &MyFrame::OnMyEvent, this, ID_MY_WINDOW);
}
// example of code generating the event
void MyWindow::SendEvent()
{
wxCommandEvent event(MY_EVENT,GetId());
event.SetEventObject(this);
// Give it some contents
event.SetString("Hello");
// Do send it
ProcessWindowEvent(event);
}
#include "MyEvent.h"
MyEvent::MyEvent(wxEventTypeeventType,intwinid, constwxString& info)
:wxEvent(winid,eventType)
{
myinfo = info;
}
voidMyEvent::SetInfo(constwxString info)
{
myinfo = info;
}
wxStringMyEvent::GetInfo()
{
returnmyinfo;
}
wxEvent*MyEvent::Clone() const
{
return newMyEvent(*this);
}
4.2 定义全新事件
1 定义新的事件类
#include <wx/event.h>
class MyEvent : public wxEvent
{
public:
MyEvent(wxEventType eventType, int winid, const wxString& info = NULL);
void SetInfo(const wxString info);
wxString GetInfo();
virtual wxEvent* Clone() const;
protected:
private:
wxString myinfo;
};
2 定义新的事件类型
wxDEFINE_EVENT
(MY_EVENT_TYPE, MyEvent);
3-1 静态事件处理机制
#define MyEventHandler(func) (&func)
#define EVT_MINE(id, func)
wx__DECLARE_EVT1(
MY_EVENT_TYPE,
id,
MyEventHandler(func))
定义事件表
BEGIN_EVENT_TABLE(MyEvtFrame, wxFrame)
…
EVT_MINE(idMyEvt,MyEvtFrame::OnMyEvent)
…
END_EVENT_TABLE()
3-2 动态事件加载
如果我们使用Bind<>方法,则勿需以上步骤,可以直接绑定事件到任意事件处理函数。
Bind(MY_EVENT_TYPE, &MyEvtFrame::OnMyEvent,
this,
idMyEvt);
4 处理事件
MyEvent myevent(MY_EVENT_TYPE, idMyEvt, _("This is my event!"));
myevent.SetEventObject(this);
ProcessWindowEvent(myevent);
5 事件的传播
有两种类型的事件:Basic Event和 Command Event。它们的区别在于传播方式。Command Event可以从子控件到父控件传递,而Basic Event则不可以。
6 窗口标示符
Window identifiers are integers that uniquely determine the window identityin the event system. There are three ways to create window id's.
7 Event Handlersvs Virtual Methods