3.5 动态事件处理方法

前面我们讨论的事件处理方法,都是静态的事件表,这也是我们处理事件最常用的方式。接下来,我们来讨论一下事件表的动态处理,也就是说在运行期改变事件表的映射关系。使用这种事件映射方法的原因,可能是你想在程序运行的不同时刻使用不同的映射关系,或者因为你使用的那种语言(例如python)不支持静态映射,或者仅仅是因为你更喜欢动态映射。因为动态映射的方法可以使你更精确的控制事件表的细节,你甚至可以单独的将事件表中的某一个条目在运行期打开或者关闭,而前面说的PushEventHandler和PopEventHandler的方法只能针对整个事件表进行处理。除此以外,动态事件处理还允许你在不同的类之间共享事件函数。

和动态事件处理相关的API有两个:wxEvtHandler::Connect和wxEvtHandler::Disconnect。大多数情况下你不需要手动调用wxEvtHandler::Disconnect函数,这个函数将在窗口类被释放的时候自动。

下面我们还用前面的MyFrame类来举例说明:

class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
private:
};

你可能已经注意到,这次我们没有使用DECLARE_EVENT_TABLE来声明一个事件表。为了动态进行事件映射,我们需要在OnInit函数中增加下面的代码:

frame->Connect( wxID_EXIT,
    wxEVT_COMMAND_MENU_SELECTED,
    wxCommandEventHandler(MyFrame::OnQuit) );
frame->Connect( wxID_ABOUT,
    wxEVT_COMMAND_MENU_SELECTED,
    wxCommandEventHandler(MyFrame::OnAbout) );

我们传递给Connect函数的三个参数分别为菜单标识符,事件标识符和事件处理函数指针。要注意这里的事件标识符 wxEVT_COMMAND_MENU_SELECTED不同于前面在静态事件表中用于表示事件映射的宏EVT_MENU,实际上EVT_MENU内部也使用了wxEVT_COMMAND_MENU_SELECTED.EVT_MENU其实也自动包含了用于对事件处理指针类型强制转换的宏 wxCommandEventHandler()。一般说来,如果事件处理函数的参数类型是wxXYZEvent,那么其处理函数的类型就应该用 wxXYZEventHandler宏进行强制转换.

如果我们希望在某个时候中止上面的事件映射,可以使用下面的方法:

frame->Disconnect( wxID_EXIT,
    wxEVT_COMMAND_MENU_SELECTED,
    wxCommandEventHandler(MyFrame::OnQuit) );
frame->Disconnect( wxID_ABOUT,
    wxEVT_COMMAND_MENU_SELECTED,
    wxCommandEventFunction(MyFrame::OnAbout) );