diff --git a/main.cpp b/main.cpp index c0e836a..7995914 100644 --- a/main.cpp +++ b/main.cpp @@ -169,6 +169,7 @@ MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) menuBar->Append(helpMenu, wxT("&Help")); // ...然后将菜单条放置在主窗口上 SetMenuBar(menuBar); + // 创建一个状态条来让一切更有趣些。 CreateStatusBar(2); SetStatusText(wxT("Welcome to wxWidgets!")); diff --git a/src/event_01.cpp b/src/event_01.cpp index 7871ee6..eef412d 100644 --- a/src/event_01.cpp +++ b/src/event_01.cpp @@ -1,30 +1,44 @@ #include "event_01.h" -BEGIN_EVENT_TABLE(MyFrame, wxFrame) -EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) -EVT_MENU(wxID_EXIT, MyFrame::OnQuit) +BEGIN_EVENT_TABLE(MainFrame, wxFrame) +EVT_MENU(wxID_ABOUT, MainFrame::OnAbout) +EVT_MENU(wxID_EXIT, MainFrame::OnQuit) + +// EVT_SIZE事件映射宏不需要标识符参数因为这个事件只会被产生这个事件的控件所处理。 +EVT_SIZE(MainFrame::OnSize) +/* + 这个例子表明,事件可以不必被产生这个事件的控件所处理。让我们假定这个按钮是MyFrame的子窗 + 口。当按钮被点击的时候,wxWidgets会首先检查wxButton类是否指定了相应的处理函数,如果找不到,则在 + 其父亲的类所属的事件表中进行查找,在这个例子中,按钮的父亲是MyFrame类型的一个实例,在其事件表中指 + 明了一个对应的处理函数,因此MyFrame::OnButtonOK函数就被调用了。类似的搜索过程不光发生在窗口控件 + 的父子继承树中,也发生在普通的类继承关系中,这意味着你可以选择在哪里定义事件的处理函数。举例来说, + 如果你设计了一个对话框,这个对话框需要响应的类似标识符为wxID_OK的command事件。但是你可能需要把 + 这个控件的创建工作留给使用你的代码的其他的程序员,只要他在创建这个控件的时候使用同样的标识符,你仍 + 然可以给这个控件为这个事件定义默认的处理函数。 +*/ +EVT_BUTTON(wxID_OK, MainFrame::OnButtonOK) END_EVENT_TABLE() bool MyApp::OnInit() { - MyFrame* frame = new MyFrame(wxT("Minimal wxWidgets App")); + MainFrame* frame = new MainFrame(wxT("Minimal wxWidgets App")); frame->Show(true); return true; } -void MyFrame::OnAbout(wxCommandEvent& event) +void MainFrame::OnAbout(wxCommandEvent& event) { wxString msg; msg.Printf(wxT("Hello and welcome to %s"), wxVERSION_STRING); wxMessageBox(msg, wxT("About Minimal"), wxOK | wxICON_INFORMATION, this); } -void MyFrame::OnQuit(wxCommandEvent& event) +void MainFrame::OnQuit(wxCommandEvent& event) { Close(); } -MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) +MainFrame::MainFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) { // 设置窗口图标 // SetIcon(wxIcon(mondrian_xpm)); @@ -41,6 +55,38 @@ MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title) menuBar->Append(helpMenu, wxT("&Help")); // ...然后将菜单条放置在主窗口上 SetMenuBar(menuBar); + + 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::OnButtonOK(wxCommandEvent& event) +{ +/* + 当用户点击了确认按钮的时候,一个新的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,这些事件都不 + 会传给事件源控件的父亲. + 这些事件不会传递给其父亲,是因为这些事件仅对产生这个事件的窗口才有意义,举例来说,把一个子窗口的重 + 绘事件发送给它的父亲,其实是没有任何意义的。 + +*/ } \ No newline at end of file diff --git a/src/event_01.h b/src/event_01.h index cb0df39..f6247b3 100644 --- a/src/event_01.h +++ b/src/event_01.h @@ -12,17 +12,48 @@ 制是最主要的方法。 */ +/* +事件表和事件处理过程 + + wxWidgets事件处理系统比起通常的虚方法机制来说要稍微复杂一点,但它的一个好处是可以避免需要实现基类 + 中所有的虚方法,因为实现所有的基类虚方法有时候是不切实际的或者是效率很低的。 + 每一个wxEvtHandler的派生类,例如frame,按钮,菜单以及文档等,都会在其内部维护一个事件表,用来告诉 + wxWidgets事件和事件处理过程的对应关系。所有继承自wxWindow的窗口类,以及应用程序类都是 + wxEvtHandler的派生类. + 要创建一个静态的事件表(意味着它是在编译期间创建的),你需要下面几个步骤: + + 1. 定义一个直接或者间接继承自wxEvtHandler的类. + 2. 为每一个你想要处理的事件定义一个处理函数。 + 3. 在这个类中使用DECLARE_EVENT_TABLE声明事件表。 + 4. 在.cpp文件中使用使用BEGIN_EVENT_TABLE和END_EVENT_TABLE实现一个事件表。 + 5. 在事件表的实现中增加事件宏,来实现从事件到事件处理过程的映射。 + + 所有的事件处理函数拥有相同的形式。他们的返回值都是void,他们都不是虚函数,他们都只有一个事件对象作 + 为参数。(如果你熟悉MFC,这可能会让你觉得轻松,因为在MFC中消息处理函数并没有一个统一的形式。)这 + 个事件对象的类型是随这个处理函数要处理的事件的变化而变化的。例如简单控件(比如按钮)的命令处理函数 + 和菜单命令的处理函数的参数都是wxCommandEvent类型,而size事件(这个事件通常是由用户改变窗口的客 + 户区尺寸而引起的)处理函数的参数则是wxSizeEvent的类型。不同的事件参数类型可以调用的方法也不相同, + 通过这些方法,你可以获得事件产生的原因以及产生这个事件的控件的值的改变情况(比如,文本框中的值的改 + 变)。当然最简单的情形是你完全不需要访问这个参数的任何方法,比如按钮点击事件。 +*/ + class MyApp : public wxApp { public: virtual bool OnInit(); }; -class MyFrame : public wxFrame { +class MainFrame : public wxFrame { public: - MyFrame(const wxString& title); + MainFrame(const wxString& title); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); +/* + 让我们来扩展一下前一章中的例子,来增加一个窗口大小改变事件的处理和一个确定按钮的处理。 +*/ + void OnSize(wxSizeEvent& event); + void OnButtonOK(wxCommandEvent& event); + private: DECLARE_EVENT_TABLE() };