Show the order in which different event handlers are called.

Update the event sample to define (as) many (as possible) event handlers for a
test button and log messages in all of the handlers to leave a trace of the
order in which they were executed.

Add a pointer to this feature of the event sample to the events overview.

Closes #11156.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-09-07 23:00:21 +00:00
parent 758f356c53
commit 7c9cc312e7
2 changed files with 168 additions and 5 deletions

View File

@@ -428,7 +428,10 @@ in simple situations where this extra flexibility is not needed.
The previous sections explain how to define event handlers but don't address The previous sections explain how to define event handlers but don't address
the question of how exactly wxWidgets finds the handler to call for the the question of how exactly wxWidgets finds the handler to call for the
given event. This section describes the algorithm used in detail. given event. This section describes the algorithm used in detail. Notice that
you may want to run the @ref page_samples_event while reading this section and
look at its code and the output when the button which can be used to test the
event handlers execution order is clicked to understand it better.
When an event is received from the windowing system, wxWidgets calls When an event is received from the windowing system, wxWidgets calls
wxEvtHandler::ProcessEvent() on the first event handler object belonging to the wxEvtHandler::ProcessEvent() on the first event handler object belonging to the
@@ -454,7 +457,7 @@ doesn't count as having handled the event and the search continues):
</li> </li>
<li value="3"> <li value="3">
The list of dynamically bind event handlers, i.e., those for which The list of dynamically bound event handlers, i.e., those for which
Bind<>() was called, is consulted. Notice that this is done before Bind<>() was called, is consulted. Notice that this is done before
checking the static event table entries, so if both a dynamic and a static checking the static event table entries, so if both a dynamic and a static
event handler match the same event, the static one is never going to be event handler match the same event, the static one is never going to be

View File

@@ -34,6 +34,9 @@
#include "../sample.xpm" #include "../sample.xpm"
#endif #endif
#include <wx/statline.h>
#include <wx/log.h>
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// event constants // event constants
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -65,8 +68,56 @@ public:
// initialization (doing it here and not in the ctor allows to have an error // initialization (doing it here and not in the ctor allows to have an error
// return: if OnInit() returns false, the application terminates) // return: if OnInit() returns false, the application terminates)
virtual bool OnInit(); virtual bool OnInit();
// these are regular event handlers used to highlight the events handling
// order
void OnClickDynamicHandlerApp(wxCommandEvent& event);
void OnClickStaticHandlerApp(wxCommandEvent& event);
// we override wxConsoleApp::FilterEvent used to highlight the events
// handling order
virtual int FilterEvent(wxEvent& event);
private:
DECLARE_EVENT_TABLE()
}; };
// Define a custom button used to highlight the events handling order
class MyEvtTestButton : public wxButton
{
public:
static long BUTTON_ID;
MyEvtTestButton(wxWindow *parent, const wxString& label)
: wxButton(parent, BUTTON_ID, label)
{
// Add a dynamic handler for this button event to button itself
Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyEvtTestButton::OnClickDynamicHandler));
}
private:
void OnClickDynamicHandler(wxCommandEvent& event)
{
wxLogMessage("Step 3 in \"How Events are Processed\":\n"
"Button::ownDynamicHandler");
event.Skip();
}
void OnClickStaticHandler(wxCommandEvent& event)
{
wxLogMessage("Step 4 in \"How Events are Processed\":\n"
"Button::ownStaticHandler");
event.Skip();
}
DECLARE_EVENT_TABLE()
};
long MyEvtTestButton::BUTTON_ID = wxNewId();
// Define a new frame type: this is going to be our main frame // Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame class MyFrame : public wxFrame
{ {
@@ -91,6 +142,11 @@ public:
void OnUpdateUIPop(wxUpdateUIEvent& event); void OnUpdateUIPop(wxUpdateUIEvent& event);
// regular event handlers used to highlight the events handling order
void OnClickDynamicHandlerFrame(wxCommandEvent& event);
void OnClickDynamicHandlerButton(wxCommandEvent& event);
void OnClickStaticHandlerFrame(wxCommandEvent& event);
private: private:
// symbolic names for the status bar fields // symbolic names for the status bar fields
enum enum
@@ -122,6 +178,10 @@ private:
// the button to whose event we connect dynamically // the button to whose event we connect dynamically
wxButton *m_btnDynamic; wxButton *m_btnDynamic;
// the button used to highlight the event handlers execution order
MyEvtTestButton *m_testBtn;
// any class wishing to process wxWidgets events must use this macro // any class wishing to process wxWidgets events must use this macro
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };
@@ -170,8 +230,19 @@ enum
// event tables and other macros for wxWidgets // event tables and other macros for wxWidgets
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// the event tables connect the wxWidgets events with the functions (event // The event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the // handlers) which process them.
BEGIN_EVENT_TABLE(MyApp, wxApp)
// Add a static handler for button Click event in the app
EVT_BUTTON(MyEvtTestButton::BUTTON_ID, MyApp::OnClickStaticHandlerApp)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(MyEvtTestButton, wxButton)
// Add a static handler to this button itself for its own event
EVT_BUTTON(BUTTON_ID, MyEvtTestButton::OnClickStaticHandler)
END_EVENT_TABLE()
// This can be also done at run-time, but for the
// simple menu events like this the static method is much simpler. // simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(MyFrame, wxFrame) BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Event_Quit, MyFrame::OnQuit) EVT_MENU(Event_Quit, MyFrame::OnQuit)
@@ -194,6 +265,9 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
// the line below would also work if OnProcessCustom() were defined as // the line below would also work if OnProcessCustom() were defined as
// taking a wxEvent (as required by EVT_CUSTOM) and not wxCommandEvent // taking a wxEvent (as required by EVT_CUSTOM) and not wxCommandEvent
//EVT_CUSTOM(wxEVT_MY_CUSTOM_COMMAND, wxID_ANY, MyFrame::OnProcessCustom) //EVT_CUSTOM(wxEVT_MY_CUSTOM_COMMAND, wxID_ANY, MyFrame::OnProcessCustom)
// Add a static handler in the parent frame for button event
EVT_BUTTON(MyEvtTestButton::BUTTON_ID, MyFrame::OnClickStaticHandlerFrame)
END_EVENT_TABLE() END_EVENT_TABLE()
BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler) BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler)
@@ -229,12 +303,51 @@ bool MyApp::OnInit()
// created initially) // created initially)
frame->Show(true); frame->Show(true);
// Add a dynamic handler at the application level for the test button
Connect(MyEvtTestButton::BUTTON_ID, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyApp::OnClickDynamicHandlerApp));
// success: wxApp::OnRun() will be called which will enter the main message // success: wxApp::OnRun() will be called which will enter the main message
// loop and the application will run. If we returned false here, the // loop and the application will run. If we returned false here, the
// application would exit immediately. // application would exit immediately.
return true; return true;
} }
// This is always the first to handle an event !
int MyApp::FilterEvent(wxEvent& event)
{
if ( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED &&
event.GetId() == MyEvtTestButton::BUTTON_ID )
{
wxLogMessage("Step 0 in \"How Events are Processed\":\n"
"App::FilterEvent");
}
return wxApp::FilterEvent(event);
}
void MyApp::OnClickDynamicHandlerApp(wxCommandEvent& event)
{
wxLogMessage("Step 7, 3 in \"How Events are Processed\":\n"
"App::DynamicHandler_InAppTable");
event.Skip();
}
void MyApp::OnClickStaticHandlerApp(wxCommandEvent& event)
{
wxLogMessage("Step 7, 4 in \"How Events are Processed\":\n"
"App::StaticHandler_InAppTable");
wxLogMessage("Button click processed, there should be no more messages "
"about handling events from the button.\n\n"
"The log below shows the order in which the handlers "
"were executed.");
wxLog::FlushActive();
event.Skip();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// main frame // main frame
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -292,6 +405,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
#endif // wxUSE_STATUSBAR #endif // wxUSE_STATUSBAR
wxPanel * const panel = new wxPanel(this); wxPanel * const panel = new wxPanel(this);
wxSizer * const mainSizer = new wxBoxSizer(wxVERTICAL);
wxSizer * const sizer = new wxBoxSizer(wxHORIZONTAL); wxSizer * const sizer = new wxBoxSizer(wxHORIZONTAL);
const wxSizerFlags centreY(wxSizerFlags().Centre().Border()); const wxSizerFlags centreY(wxSizerFlags().Centre().Border());
sizer->Add(new wxStaticText(panel, wxID_ANY, sizer->Add(new wxStaticText(panel, wxID_ANY,
@@ -299,7 +413,29 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
centreY); centreY);
m_btnDynamic = new wxButton(panel, Event_Dynamic, "&Dynamic button"); m_btnDynamic = new wxButton(panel, Event_Dynamic, "&Dynamic button");
sizer->Add(m_btnDynamic, centreY); sizer->Add(m_btnDynamic, centreY);
panel->SetSizer(sizer);
mainSizer->Add(sizer, 1, wxEXPAND);
mainSizer->Add(new wxStaticLine(panel), 0, wxEXPAND);
mainSizer->Add(new wxStaticLine(panel), 0, wxEXPAND);
m_testBtn = new MyEvtTestButton(panel, "Test Event Handlers Execution Order");
// After being created, an instance of MyEvtTestButton already has its own
// event handlers (see class definition);
// Add a dynamic handler for this button event in the parent frame
Connect(m_testBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyFrame::OnClickDynamicHandlerFrame));
// Bind a method of this frame (notice "this" argument!) to the button
// itself
m_testBtn->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyFrame::OnClickDynamicHandlerButton),
NULL,
this);
mainSizer->Add(m_testBtn);
panel->SetSizer(mainSizer);
} }
MyFrame::~MyFrame() MyFrame::~MyFrame()
@@ -330,10 +466,34 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
wxOK | wxICON_INFORMATION, this); wxOK | wxICON_INFORMATION, this);
} }
void MyFrame::OnClickStaticHandlerFrame(wxCommandEvent& event)
{
wxLogMessage("Step 6, 4 in \"How Events are Processed\":\n"
"parentWin::StaticHandler_InFrameTable");
event.Skip();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// dynamic event handling stuff // dynamic event handling stuff
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void MyFrame::OnClickDynamicHandlerFrame(wxCommandEvent& event)
{
wxLogMessage("Step 6, 3 in \"How Events are Processed\":\n"
"parentWin::DynamicHandler_InFrameTable");
event.Skip();
}
void MyFrame::OnClickDynamicHandlerButton(wxCommandEvent& event)
{
wxLogMessage("Step 3 in \"How Events are Processed\":\n"
"parentWin::DynamicHandler_InButtonTable");
event.Skip();
}
void MyFrame::OnDynamic(wxCommandEvent& event) void MyFrame::OnDynamic(wxCommandEvent& event)
{ {
wxString origin; wxString origin;