From d07cc4295e53be5571b4c0cda08fc5756136aa9e Mon Sep 17 00:00:00 2001 From: taynpg Date: Thu, 25 Jan 2024 14:43:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E6=80=81=E4=BA=8B=E4=BB=B6=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/event_demo.cpp | 68 ++++++++++++++++++++++++++++------------------ src/event_demo.h | 33 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/event_demo.cpp b/src/event_demo.cpp index 8efa180..0bd76e9 100644 --- a/src/event_demo.cpp +++ b/src/event_demo.cpp @@ -1,5 +1,7 @@ #include "event_demo.h" +#ifndef USE_DYNAMIC_CONNECT +// 静态链接 BEGIN_EVENT_TABLE(MainFrame, wxFrame) EVT_MENU(wxID_ABOUT, MainFrame::OnAbout) EVT_MENU(wxID_EXIT, MainFrame::OnQuit) @@ -18,11 +20,28 @@ EVT_SIZE(MainFrame::OnSize) */ EVT_BUTTON(wxID_OK, MainFrame::OnButtonOK) END_EVENT_TABLE() +#endif bool MyApp::OnInit() { MainFrame* frame = new MainFrame(wxT("Minimal wxWidgets App")); frame->Show(true); + +#ifdef USE_DYNAMIC_CONNECT +/* + 三个参数分别为菜单标识符,事件标识符和事件处理函数指针。要注意这里的事件标 + 识符 wxEVT_COMMAND_MENU_SELECTED不同于前面在静态事件表中用于表示事件映射的宏EVT_MENU,实 + 际上EVT_MENU内部也使用了wxEVT_COMMAND_MENU_SELECTED.EVT_MENU其实也自动包含了用于对事 + 件处理指针类型强制转换的宏 wxCommandEventHandler()。一般说来,如果事件处理函数的参数类型是 + wxXYZEvent,那么其处理函数的类型就应该用 wxXYZEventHandler宏进行强制转换. + + 有对应的 frame->Disconnect +*/ + frame->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MainFrame::OnQuit)); + frame->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MainFrame::OnAbout)); +#endif return true; } @@ -33,10 +52,7 @@ void MainFrame::OnAbout(wxCommandEvent& event) wxMessageBox(msg, wxT("About Minimal"), wxOK | wxICON_INFORMATION, this); } -void MainFrame::OnQuit(wxCommandEvent& event) -{ - Close(); -} +void MainFrame::OnQuit(wxCommandEvent& event) { Close(); } MainFrame::MainFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) { @@ -56,37 +72,37 @@ MainFrame::MainFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) // ...然后将菜单条放置在主窗口上 SetMenuBar(menuBar); - wxButton* button = new wxButton(this, wxID_OK, wxT("OK"), - wxPoint(200, 200)); + wxButton* button = + new wxButton(this, wxID_OK, wxT("OK"), wxPoint(200, 200)); CreateStatusBar(2); SetStatusText(wxT("Welcome to wxWidgets!")); } -void MainFrame::OnSize(wxSizeEvent& event) -{ - -} +void MainFrame::OnSize(wxSizeEvent& event) {} void MainFrame::OnButtonOK(wxCommandEvent& event) { -/* - 当用户点击了确认按钮的时候,一个新的wxCommandEvent事件被创建,其中包 - 含标识符wxID_OK和事件类型 wxEVT_COMMAND_BUTTON_CLICKED,然后这个按钮的事件表开始通过 - wxEvtHandler::ProcessEvent函数进行匹配,事件表中的每一个条目都会去尝试匹配,然后是其父类wxControl - 的事件表,然后是wxWindow的。如果都没有匹配到, wxWidgets会搜索其父亲的类事件表,然后就找到了一 - 条匹配条目:EVT_BUTTON(wxID_OK,MyFrame::OnButtonOK) + /* + 当用户点击了确认按钮的时候,一个新的wxCommandEvent事件被创建,其中包 + 含标识符wxID_OK和事件类型 + wxEVT_COMMAND_BUTTON_CLICKED,然后这个按钮的事件表开始通过 + wxEvtHandler::ProcessEvent函数进行匹配,事件表中的每一个条目都会去尝试匹配,然后是其父类wxControl + 的事件表,然后是wxWindow的。如果都没有匹配到, + wxWidgets会搜索其父亲的类事件表,然后就找到了一 + 条匹配条目:EVT_BUTTON(wxID_OK,MyFrame::OnButtonOK) - 简单来讲就是:先匹配自己的处理事件函数(若有继承往上找),没有去父类找。 + 简单来讲就是:先匹配自己的处理事件函数(若有继承往上找),没有去父类找。 - 只有Command事件(其事件类型直接或者间接的继承自wxCommandEvent)才会被递归的应用 - 到其父亲的事件表。通常这是wxWidgets的用户经常会感到困惑的地方,因此我们把那些不会传递给其父亲的事 - 件表的事件列举如下:wxActivate, wxCloseEvent, wxEraseEvent, wxFocusEvent, wxKeyEvent, wxIdleEvent, - wxInitDialogEvent, wxJoystickEvent, wxMenuEvent, wxMouseEvent, wxMoveEvent, wxPaintEvent, - wxQueryLayoutInfoEvent, wxSizeEvent, wxScrollWinEvent, 和wxSysColourChangedEvent,这些事件都不 - 会传给事件源控件的父亲. - 这些事件不会传递给其父亲,是因为这些事件仅对产生这个事件的窗口才有意义,举例来说,把一个子窗口的重 - 绘事件发送给它的父亲,其实是没有任何意义的。 + 只有Command事件(其事件类型直接或者间接的继承自wxCommandEvent)才会被递归的应用 + 到其父亲的事件表。通常这是wxWidgets的用户经常会感到困惑的地方,因此我们把那些不会传递给其父亲的事 + 件表的事件列举如下:wxActivate, wxCloseEvent, wxEraseEvent, + wxFocusEvent, wxKeyEvent, wxIdleEvent, wxInitDialogEvent, + wxJoystickEvent, wxMenuEvent, wxMouseEvent, wxMoveEvent, wxPaintEvent, + wxQueryLayoutInfoEvent, wxSizeEvent, wxScrollWinEvent, + 和wxSysColourChangedEvent,这些事件都不 会传给事件源控件的父亲. + 这些事件不会传递给其父亲,是因为这些事件仅对产生这个事件的窗口才有意义,举例来说,把一个子窗口的重 + 绘事件发送给它的父亲,其实是没有任何意义的。 -*/ + */ } \ No newline at end of file diff --git a/src/event_demo.h b/src/event_demo.h index 2287b8f..a9f6037 100644 --- a/src/event_demo.h +++ b/src/event_demo.h @@ -3,6 +3,8 @@ #include "wx/wx.h" +#define USE_DYNAMIC_CONNECT + /* 应用程序一直停留在一个循环中,等待着来自用户或者其他地方 (比如窗口刷新或网络连接)的事件,一旦收到某种事件,应用程序就将其扔给处理这个事件的函数。虽然看上 @@ -66,6 +68,37 @@ } */ +/* +挂载事件表: + 你并不一定非要实现继承自某个类的新类,才可以改变它的事件表。对于那些继承自wxWindow的类来说,有另 + 外一种可取代的方法。你可以通过实现一个新的直接继承自wxEvtHandler的新类,然后定义这个新类事件表,然 + 后使用wxWindow::PushEventHandler函数将这个事件表压入到某个窗口类的事件表栈中。最后压入的那个事件 + 表在事件匹配过程中将会被最先匹配,如果在其中没有匹配到对应的事件处理过程,那么栈中以前的事件表仍将 + 被匹配,如此类推。你还可以用wxWindow::PopEventHandler函数来弹出最顶层的事件表,如果你给 + wxWindow:: PopEventHandler函数传递的是True的参数,那么这个弹出的事件表将被删除。 + 这种方法可以避免大量的类重载,也使不同的类的实例共享同一个事件表成为可能。 + 有时候,你需要手动调用窗口类的事件表,这时候你应该使用wxWindow::GetEventHandler方法,而不是直接 + 使用调用这个窗口类的成员函数。虽然wxWindow::GetEventHandler通常返回这个窗口类本身。但是如果你之 + 前曾经使用 PushEventHandler压入另外一个事件表,那么函数将会返回处于最顶层的事件表。因此使用 + wxWindow:: GetEventHandler函数才可以保证事件被正确的处理。 + PushEventHandler的方法通常用来临时的或者永久的改变图形界面的行为。举例来说,加入你想在你的应用程 + 序实现对话框编辑的功能。你可以捕获这个对话框和它的内部控件的所有的鼠标事件,先使用你自己的事件表处 + 理这些事件,来进行类似拖拽控件,改变控件大小以及移动控件动作。这在联机教学中也是很有用技术。你可以 + 在你自己的事件表中过滤收到的事件,如果是可以接受的,则调用wxEvent::Skip函数正常处理。 +*/ + +/* +动态事件处理 + 前面我们讨论的事件处理方法,都是静态的事件表,这也是我们处理事件最常用的方式。接下来,我们来讨论一 + 下事件表的动态处理,也就是说在运行期改变事件表的映射关系。使用这种事件映射方法的原因,可能是你想在 + 程序运行的不同时刻使用不同的映射关系,或者因为你使用的那种语言(例如python)不支持静态映射,或者仅仅 + 是因为你更喜欢动态映射。因为动态映射的方法可以使你更精确的控制事件表的细节,你甚至可以单独的将事件 + 表中的某一个条目在运行期打开或者关闭,而前面说的PushEventHandler和PopEventHandler的方法只能针对 + 整个事件表进行处理。除此以外,动态事件处理还允许你在不同的类之间共享事件函数。 + 和动态事件处理相关的API有两个:wxEvtHandler::Connect和wxEvtHandler::Disconnect。大多数情况下你不需 + 要手动调用wxEvtHandler::Disconnect函数,这个函数将在窗口类被释放的时候自动。 +*/ + class MyApp : public wxApp { public: virtual bool OnInit();