Merge branch 'helloworld-doc'

Modernize "Hello world" page: Bind(), C++11 etc.

Closes https://github.com/wxWidgets/wxWidgets/pull/317
This commit is contained in:
Vadim Zeitlin
2016-11-16 18:02:28 +01:00

View File

@@ -51,24 +51,25 @@ 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 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. 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 Finally, the way to react to such events must be done in "event handlers" which
sample, we react to three menu items, one for our custom menu command and two are just functions (or functors, including lambdas if you're using C++11)
for the standard "Exit" and "About" commands (any program should normally taking the @c event parameter of the type corresponding to the event being
implement the latter two). Notice that these handlers don't need to be neither handled, e.g. wxCommandEvent for the events from simple controls such as
virtual nor public. 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 @code
class MyFrame: public wxFrame class MyFrame: public wxFrame
{ {
public: public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); MyFrame();
private: private:
void OnHello(wxCommandEvent& event); void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event); void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event); void OnAbout(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
}; };
@endcode @endcode
@@ -83,47 +84,31 @@ enum
}; };
@endcode @endcode
Notice that you don't need to define identifiers for the "About" and "Exit". We Notice that you don't need to define identifiers for the "About" and "Exit" as
then proceed to actually implement an event table in which the events are wxWidgets already predefines and the standard values such as wxID_ABOUT and
routed to their respective handler functions in the class MyFrame. wxID_EXIT should be used whenever possible, as they can be handled in a special
way by a particular platform.
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
As in all programs there must be a "main" function. Under wxWidgets main is 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 implemented inside ::wxIMPLEMENT_APP() macro, which creates an application
the program. instance of the specified class and starts running the GUI event loop. It is
used simply as:
@code @code
wxIMPLEMENT_APP(MyApp) wxIMPLEMENT_APP(MyApp);
@endcode @endcode
As mentioned above, wxApp::OnInit() is called upon startup and should be used 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 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") main window (or several). As frames are created hidden by default, to allow
and a position and start-up size. One frame can also be declared to be the top creating their child windows before showing them, we also need to explicitly
window. Returning @true indicates a successful initialization. show it to make it appear on the screen. Finally, we return @true from this
method to indicate successful initialization:
@code @code
bool MyApp::OnInit() bool MyApp::OnInit()
{ {
MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) ); MyFrame *frame = new MyFrame();
frame->Show( true ); frame->Show( true );
return true; return true;
} }
@@ -134,8 +119,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. window. Both have to be associated with the frame with respective calls.
@code @code
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, title, pos, size) : wxFrame(NULL, wxID_ANY, "Hello World")
{ {
wxMenu *menuFile = new wxMenu; wxMenu *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
@@ -154,7 +139,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
CreateStatusBar(); CreateStatusBar();
SetStatusText( "Welcome to wxWidgets!" ); SetStatusText( "Welcome to wxWidgets!" );
}
... continued below ...
@endcode @endcode
Notice that we don't need to specify the labels for the standard menu items Notice that we don't need to specify the labels for the standard menu items
@@ -163,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 platform making your program behaviour more native. For this reason you should
prefer reusing the standard ids (see @ref page_stockitems) if possible. 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 Here are the standard event handlers implementations. MyFrame::OnExit() closes
the main window by calling Close(). The parameter @true indicates that other 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?". windows have no veto power such as after asking "Do you really want to close?".
@@ -197,6 +209,17 @@ void MyFrame::OnHello(wxCommandEvent& event)
} }
@endcode @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: Here is the entire program that can be copied and pasted:
@code @code
@@ -218,14 +241,12 @@ public:
class MyFrame: public wxFrame class MyFrame: public wxFrame
{ {
public: public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); MyFrame();
private: private:
void OnHello(wxCommandEvent& event); void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event); void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event); void OnAbout(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
}; };
enum enum
@@ -233,23 +254,17 @@ enum
ID_Hello = 1 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); wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit() bool MyApp::OnInit()
{ {
MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) ); MyFrame *frame = new MyFrame();
frame->Show( true ); frame->Show( true );
return true; return true;
} }
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, title, pos, size) : wxFrame(NULL, wxID_ANY, "Hello World")
{ {
wxMenu *menuFile = new wxMenu; wxMenu *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
@@ -268,6 +283,10 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
CreateStatusBar(); CreateStatusBar();
SetStatusText( "Welcome to wxWidgets!" ); 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) void MyFrame::OnExit(wxCommandEvent& event)