From f25956512359e60cd8161165a83cc4309c1adfeb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Aug 2016 18:32:54 +0200 Subject: [PATCH 1/4] Improve description of wxIMPLEMENT_APP() on the "Hello world" page Also add the missing semicolon after it, so that if anybody copies and pastes this line from the documentation, it actually would compile. --- docs/doxygen/overviews/helloworld.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/doxygen/overviews/helloworld.h b/docs/doxygen/overviews/helloworld.h index 7a06ccf66a..8663e0786a 100644 --- a/docs/doxygen/overviews/helloworld.h +++ b/docs/doxygen/overviews/helloworld.h @@ -107,11 +107,12 @@ wxEND_EVENT_TABLE() @endcode As in all programs there must be a "main" function. Under wxWidgets main is -implemented using this macro, which creates an application instance and starts -the program. +implemented inside ::wxIMPLEMENT_APP() macro, which creates an application +instance of the specified class and starts running the GUI event loop. It is +used simply as: @code -wxIMPLEMENT_APP(MyApp) +wxIMPLEMENT_APP(MyApp); @endcode As mentioned above, wxApp::OnInit() is called upon startup and should be used From 7f26deb13ec09efe4b63d7753107af83b70bbd49 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Aug 2016 18:37:29 +0200 Subject: [PATCH 2/4] Don't hard-code position and size for "Hello World" frame This is not good practice and we shouldn't encourage people to do this. --- docs/doxygen/overviews/helloworld.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/doxygen/overviews/helloworld.h b/docs/doxygen/overviews/helloworld.h index 8663e0786a..71a784d0dc 100644 --- a/docs/doxygen/overviews/helloworld.h +++ b/docs/doxygen/overviews/helloworld.h @@ -61,7 +61,7 @@ virtual nor public. class MyFrame: public wxFrame { public: - MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + MyFrame(); private: void OnHello(wxCommandEvent& event); @@ -117,14 +117,15 @@ wxIMPLEMENT_APP(MyApp); As mentioned above, wxApp::OnInit() is called upon startup and should be used to initialize the program, maybe showing a "splash screen" and creating the -main window (or several). The frame should get a title bar text ("Hello World") -and a position and start-up size. One frame can also be declared to be the top -window. Returning @true indicates a successful initialization. +main window (or several). As frames are created hidden by default, to allow +creating their child windows before showing them, we also need to explicitly +show it to make it appear on the screen. Finally, we return @true from this +method to indicate successful initialization: @code bool MyApp::OnInit() { - MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) ); + MyFrame *frame = new MyFrame(); frame->Show( true ); return true; } @@ -135,8 +136,8 @@ menu items as well as a status bar to be shown at the bottom of the main window. Both have to be associated with the frame with respective calls. @code -MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) - : wxFrame(NULL, wxID_ANY, title, pos, size) +MyFrame::MyFrame() + : wxFrame(NULL, wxID_ANY, "Hello World") { wxMenu *menuFile = new wxMenu; menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", @@ -219,7 +220,7 @@ public: class MyFrame: public wxFrame { public: - MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + MyFrame(); private: void OnHello(wxCommandEvent& event); @@ -244,13 +245,13 @@ wxIMPLEMENT_APP(MyApp); bool MyApp::OnInit() { - MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) ); + MyFrame *frame = new MyFrame(); frame->Show( true ); return true; } -MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) - : wxFrame(NULL, wxID_ANY, title, pos, size) +MyFrame::MyFrame() + : wxFrame(NULL, wxID_ANY, "Hello World") { wxMenu *menuFile = new wxMenu; menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", From 2d56fb5298727daa9a3b83e9e48fd8ce79b3db98 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Aug 2016 18:49:30 +0200 Subject: [PATCH 3/4] Use Bind() instead of event tables on the "Hello World" page Let the new users know that Bind() is the preferred way to handle events in modern wxWidgets. --- docs/doxygen/overviews/helloworld.h | 82 ++++++++++++++++------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/docs/doxygen/overviews/helloworld.h b/docs/doxygen/overviews/helloworld.h index 71a784d0dc..2c60c78c5b 100644 --- a/docs/doxygen/overviews/helloworld.h +++ b/docs/doxygen/overviews/helloworld.h @@ -51,11 +51,14 @@ menu and a status bar in its constructor. Also, any class that wishes to respond to any "event" (such as mouse clicks or messages from the menu or a button) must declare an event table using the macro below. -Finally, the way to react to such events must be done in "handlers". In our -sample, we react to three menu items, one for our custom menu command and two -for the standard "Exit" and "About" commands (any program should normally -implement the latter two). Notice that these handlers don't need to be neither -virtual nor public. +Finally, the way to react to such events must be done in "event handlers" which +are just functions (or functors, including lambdas if you're using C++11) +taking the @c event parameter of the type corresponding to the event being +handled, e.g. wxCommandEvent for the events from simple controls such as +buttons, text fields and also menu items. In our sample, we react to three menu +items, one for our custom menu command and two for the standard "Exit" and +"About" commands (any program should normally implement the latter two). Notice +that these handlers don't need to be neither virtual nor public. @code class MyFrame: public wxFrame @@ -67,8 +70,6 @@ private: void OnHello(wxCommandEvent& event); void OnExit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); - - wxDECLARE_EVENT_TABLE(); }; @endcode @@ -83,28 +84,10 @@ enum }; @endcode -Notice that you don't need to define identifiers for the "About" and "Exit". We -then proceed to actually implement an event table in which the events are -routed to their respective handler functions in the class MyFrame. - -There are predefined macros for routing all common events, ranging from the -selection of a list box entry to a resize event when a user resizes a window on -the screen. If @c wxID_ANY is given as the ID, the given handler will be -invoked for any event of the specified type, so that you could add just one -entry in the event table for all menu commands or all button commands etc. - -The origin of the event can still be distinguished in the event handler as the -(only) parameter in an event handler is a reference to a wxEvent object, which -holds various information about the event (such as the ID of and a pointer to -the class, which emitted the event). - -@code -wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(ID_Hello, MyFrame::OnHello) - EVT_MENU(wxID_EXIT, MyFrame::OnExit) - EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) -wxEND_EVENT_TABLE() -@endcode +Notice that you don't need to define identifiers for the "About" and "Exit" as +wxWidgets already predefines and the standard values such as wxID_ABOUT and +wxID_EXIT should be used whenever possible, as they can be handled in a special +way by a particular platform. As in all programs there must be a "main" function. Under wxWidgets main is implemented inside ::wxIMPLEMENT_APP() macro, which creates an application @@ -156,7 +139,8 @@ MyFrame::MyFrame() CreateStatusBar(); SetStatusText( "Welcome to wxWidgets!" ); -} + + ... continued below ... @endcode Notice that we don't need to specify the labels for the standard menu items @@ -165,6 +149,32 @@ translated) labels and also standard accelerators correct for the current platform making your program behaviour more native. For this reason you should prefer reusing the standard ids (see @ref page_stockitems) if possible. +We also have to actually connect our event handlers to the events we want to +handle in them, by calling Bind() to send all the menu events, identified by +wxEVT_MENU event type, with the specified ID to the given function. The +parameters we pass to Bind() are + +-# The event type, e.g. wxEVT_MENU or wxEVT_BUTTON or wxEVT_SIZE or one + of many other events used by wxWidgets. +-# Pointer to the member function to call and the object to call it on. In + this case we just call our own function, hence we pass `this` for this + object itself, but we could call a member function of another object too. + And we could could also use a non-member function here, and, in fact, + anything that can be called passing it a wxCommandEvent could be used here. +-# The optional identifier allowing to select just some events of wxEVT_MENU + type, namely those from the menu item with the given ID, instead of handling + all of them in the provided handler. This is especially useful with the menu + items and rarely used with other kinds of events. + +@code + ... continued from above ... + + Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello); + Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT); + Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT); +} +@endcode + Here are the standard event handlers implementations. MyFrame::OnExit() closes the main window by calling Close(). The parameter @true indicates that other windows have no veto power such as after asking "Do you really want to close?". @@ -226,8 +236,6 @@ private: void OnHello(wxCommandEvent& event); void OnExit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); - - wxDECLARE_EVENT_TABLE(); }; enum @@ -235,12 +243,6 @@ enum ID_Hello = 1 }; -wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(ID_Hello, MyFrame::OnHello) - EVT_MENU(wxID_EXIT, MyFrame::OnExit) - EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) -wxEND_EVENT_TABLE() - wxIMPLEMENT_APP(MyApp); bool MyApp::OnInit() @@ -270,6 +272,10 @@ MyFrame::MyFrame() CreateStatusBar(); SetStatusText( "Welcome to wxWidgets!" ); + + Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello); + Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT); + Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT); } void MyFrame::OnExit(wxCommandEvent& event) From 8072481f86e6d424bcd2d583ea6070439f99d7ff Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Aug 2016 14:01:52 +0200 Subject: [PATCH 4/4] Show using C++11 lambda in the "Hello world" example This is so useful, that it should be mentioned even on this introductory page. --- docs/doxygen/overviews/helloworld.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/doxygen/overviews/helloworld.h b/docs/doxygen/overviews/helloworld.h index 2c60c78c5b..8b2fefa5f7 100644 --- a/docs/doxygen/overviews/helloworld.h +++ b/docs/doxygen/overviews/helloworld.h @@ -209,6 +209,17 @@ void MyFrame::OnHello(wxCommandEvent& event) } @endcode +@note In C++11 programs, it can be convenient to use unnamed lambdas instead of + functions for event handlers, especially when handling events from the + controls as this allows to keep the code creating the control and handling + its event together in the same place. Here, for example, we could replace + the wxID_EXIT handler with just + +@code + Bind(wxEVT_MENU, [=](wxCommandEvent&) { Close(true); }, wxID_EXIT); +@endcode + + Here is the entire program that can be copied and pasted: @code