1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWidgets sample demonstrating different event usage
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001-2009 Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
27 // for all others, include the necessary headers (this file is usually all you
28 // need because it includes almost all "standard" wxWidgets headers)
34 #include "../sample.xpm"
37 #include <wx/statline.h>
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 // define a custom event type (we don't need a separate declaration here but
45 // usually you would use a matching wxDECLARE_EVENT in a header)
46 wxDEFINE_EVENT(wxEVT_MY_CUSTOM_COMMAND
, wxCommandEvent
);
48 // it may also be convenient to define an event table macro for this event type
49 #define EVT_MY_CUSTOM_COMMAND(id, fn) \
50 DECLARE_EVENT_TABLE_ENTRY( \
51 wxEVT_MY_CUSTOM_COMMAND, id, wxID_ANY, \
52 wxCommandEventHandler(fn), \
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // Define a new application type, each program should derive a class from wxApp
61 class MyApp
: public wxApp
64 // override base class virtuals
65 // ----------------------------
67 // this one is called on application startup and is a good place for the app
68 // initialization (doing it here and not in the ctor allows to have an error
69 // return: if OnInit() returns false, the application terminates)
70 virtual bool OnInit();
72 // these are regular event handlers used to highlight the events handling
74 void OnClickDynamicHandlerApp(wxCommandEvent
& event
);
75 void OnClickStaticHandlerApp(wxCommandEvent
& event
);
77 // we override wxConsoleApp::FilterEvent used to highlight the events
79 virtual int FilterEvent(wxEvent
& event
);
85 // Define a custom button used to highlight the events handling order
86 class MyEvtTestButton
: public wxButton
89 static long BUTTON_ID
;
91 MyEvtTestButton(wxWindow
*parent
, const wxString
& label
)
92 : wxButton(parent
, BUTTON_ID
, label
)
94 // Add a dynamic handler for this button event to button itself
95 Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
96 wxCommandEventHandler(MyEvtTestButton::OnClickDynamicHandler
));
100 void OnClickDynamicHandler(wxCommandEvent
& event
)
102 wxLogMessage("Step 3 in \"How Events are Processed\":\n"
103 "Button::ownDynamicHandler");
108 void OnClickStaticHandler(wxCommandEvent
& event
)
110 wxLogMessage("Step 4 in \"How Events are Processed\":\n"
111 "Button::ownStaticHandler");
116 DECLARE_EVENT_TABLE()
119 long MyEvtTestButton::BUTTON_ID
= wxNewId();
121 // Define a new frame type: this is going to be our main frame
122 class MyFrame
: public wxFrame
126 MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
);
129 void OnQuit(wxCommandEvent
& event
);
130 void OnAbout(wxCommandEvent
& event
);
131 #ifdef wxHAS_EVENT_BIND
132 void OnBind(wxCommandEvent
& event
);
133 #endif // wxHAS_EVENT_BIND
134 void OnConnect(wxCommandEvent
& event
);
135 void OnDynamic(wxCommandEvent
& event
);
136 void OnPushEventHandler(wxCommandEvent
& event
);
137 void OnPopEventHandler(wxCommandEvent
& event
);
138 void OnTest(wxCommandEvent
& event
);
140 void OnFireCustom(wxCommandEvent
& event
);
141 void OnProcessCustom(wxCommandEvent
& event
);
143 void OnUpdateUIPop(wxUpdateUIEvent
& event
);
145 // regular event handlers used to highlight the events handling order
146 void OnClickDynamicHandlerFrame(wxCommandEvent
& event
);
147 void OnClickDynamicHandlerButton(wxCommandEvent
& event
);
148 void OnClickStaticHandlerFrame(wxCommandEvent
& event
);
151 // symbolic names for the status bar fields
159 void UpdateDynamicStatus(bool on
)
164 SetStatusText("You can now use \"Dynamic\" item in the menu");
165 SetStatusText("Dynamic: on", Status_Dynamic
);
169 SetStatusText("You can no more use \"Dynamic\" item in the menu");
170 SetStatusText("Dynamic: off", Status_Dynamic
);
172 #endif // wxUSE_STATUSBAR
175 // number of pushed event handlers
178 // the button to whose event we connect dynamically
179 wxButton
*m_btnDynamic
;
181 // the button used to highlight the event handlers execution order
182 MyEvtTestButton
*m_testBtn
;
185 // any class wishing to process wxWidgets events must use this macro
186 DECLARE_EVENT_TABLE()
189 // Define a custom event handler
190 class MyEvtHandler
: public wxEvtHandler
193 MyEvtHandler(size_t level
) { m_level
= level
; }
195 void OnTest(wxCommandEvent
& event
)
197 wxLogMessage(wxT("This is the pushed test event handler #%u"), m_level
);
199 // if we don't skip the event, the other event handlers won't get it:
200 // try commenting out this line and see what changes
207 DECLARE_EVENT_TABLE()
210 // ----------------------------------------------------------------------------
212 // ----------------------------------------------------------------------------
214 // IDs for the controls and the menu commands
229 // ----------------------------------------------------------------------------
230 // event tables and other macros for wxWidgets
231 // ----------------------------------------------------------------------------
233 // The event tables connect the wxWidgets events with the functions (event
234 // handlers) which process them.
235 BEGIN_EVENT_TABLE(MyApp
, wxApp
)
236 // Add a static handler for button Click event in the app
237 EVT_BUTTON(MyEvtTestButton::BUTTON_ID
, MyApp::OnClickStaticHandlerApp
)
240 BEGIN_EVENT_TABLE(MyEvtTestButton
, wxButton
)
241 // Add a static handler to this button itself for its own event
242 EVT_BUTTON(BUTTON_ID
, MyEvtTestButton::OnClickStaticHandler
)
245 // This can be also done at run-time, but for the
246 // simple menu events like this the static method is much simpler.
247 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
248 EVT_MENU(Event_Quit
, MyFrame::OnQuit
)
249 EVT_MENU(Event_About
, MyFrame::OnAbout
)
251 #ifdef wxHAS_EVENT_BIND
252 EVT_MENU(Event_Bind
, MyFrame::OnBind
)
253 #endif // wxHAS_EVENT_BIND
254 EVT_MENU(Event_Connect
, MyFrame::OnConnect
)
256 EVT_MENU(Event_Custom
, MyFrame::OnFireCustom
)
257 EVT_MENU(Event_Test
, MyFrame::OnTest
)
258 EVT_MENU(Event_Push
, MyFrame::OnPushEventHandler
)
259 EVT_MENU(Event_Pop
, MyFrame::OnPopEventHandler
)
261 EVT_UPDATE_UI(Event_Pop
, MyFrame::OnUpdateUIPop
)
263 EVT_MY_CUSTOM_COMMAND(wxID_ANY
, MyFrame::OnProcessCustom
)
265 // the line below would also work if OnProcessCustom() were defined as
266 // taking a wxEvent (as required by EVT_CUSTOM) and not wxCommandEvent
267 //EVT_CUSTOM(wxEVT_MY_CUSTOM_COMMAND, wxID_ANY, MyFrame::OnProcessCustom)
269 // Add a static handler in the parent frame for button event
270 EVT_BUTTON(MyEvtTestButton::BUTTON_ID
, MyFrame::OnClickStaticHandlerFrame
)
273 BEGIN_EVENT_TABLE(MyEvtHandler
, wxEvtHandler
)
274 EVT_MENU(Event_Test
, MyEvtHandler::OnTest
)
277 // Create a new application object: this macro will allow wxWidgets to create
278 // the application object during program execution (it's better than using a
279 // static object for many reasons) and also declares the accessor function
280 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
284 // ============================================================================
286 // ============================================================================
288 // ----------------------------------------------------------------------------
289 // the application class
290 // ----------------------------------------------------------------------------
292 // 'Main program' equivalent: the program execution "starts" here
295 if ( !wxApp::OnInit() )
298 // create the main application window
299 MyFrame
*frame
= new MyFrame(wxT("Event wxWidgets Sample"),
300 wxPoint(50, 50), wxSize(600, 340));
302 // and show it (the frames, unlike simple controls, are not shown when
303 // created initially)
306 // Add a dynamic handler at the application level for the test button
307 Connect(MyEvtTestButton::BUTTON_ID
, wxEVT_COMMAND_BUTTON_CLICKED
,
308 wxCommandEventHandler(MyApp::OnClickDynamicHandlerApp
));
310 // success: wxApp::OnRun() will be called which will enter the main message
311 // loop and the application will run. If we returned false here, the
312 // application would exit immediately.
316 // This is always the first to handle an event !
317 int MyApp::FilterEvent(wxEvent
& event
)
319 if ( event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED
&&
320 event
.GetId() == MyEvtTestButton::BUTTON_ID
)
322 wxLogMessage("Step 0 in \"How Events are Processed\":\n"
326 return wxApp::FilterEvent(event
);
329 void MyApp::OnClickDynamicHandlerApp(wxCommandEvent
& event
)
331 wxLogMessage("Step 7, 3 in \"How Events are Processed\":\n"
332 "App::DynamicHandler_InAppTable");
337 void MyApp::OnClickStaticHandlerApp(wxCommandEvent
& event
)
339 wxLogMessage("Step 7, 4 in \"How Events are Processed\":\n"
340 "App::StaticHandler_InAppTable");
342 wxLogMessage("Button click processed, there should be no more messages "
343 "about handling events from the button.\n\n"
344 "The log below shows the order in which the handlers "
346 wxLog::FlushActive();
351 // ----------------------------------------------------------------------------
353 // ----------------------------------------------------------------------------
356 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
357 : wxFrame(NULL
, wxID_ANY
, title
, pos
, size
)
359 SetIcon(wxICON(sample
));
366 wxMenu
*menuFile
= new wxMenu
;
368 menuFile
->Append(Event_About
, wxT("&About...\tCtrl-A"), wxT("Show about dialog"));
369 menuFile
->AppendSeparator();
370 menuFile
->Append(Event_Quit
, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
372 wxMenu
*menuEvent
= new wxMenu
;
373 #ifdef wxHAS_EVENT_BIND
374 menuEvent
->AppendCheckItem(Event_Bind
, "&Bind\tCtrl-B",
375 "Bind or unbind a dynamic event handler");
376 #endif // wxHAS_EVENT_BIND
377 menuEvent
->AppendCheckItem(Event_Connect
, wxT("&Connect\tCtrl-C"),
378 wxT("Connect or disconnect the dynamic event handler"));
379 menuEvent
->Append(Event_Dynamic
, wxT("&Dynamic event\tCtrl-D"),
380 wxT("Dynamic event sample - only works after Connect"));
381 menuEvent
->AppendSeparator();
382 menuEvent
->Append(Event_Push
, wxT("&Push event handler\tCtrl-P"),
383 wxT("Push event handler for test event"));
384 menuEvent
->Append(Event_Pop
, wxT("P&op event handler\tCtrl-O"),
385 wxT("Pop event handler for test event"));
386 menuEvent
->Append(Event_Test
, wxT("Test event\tCtrl-T"),
387 wxT("Test event processed by pushed event handler"));
388 menuEvent
->AppendSeparator();
389 menuEvent
->Append(Event_Custom
, wxT("Fire c&ustom event\tCtrl-U"),
390 wxT("Generate a custom event"));
392 // now append the freshly created menu to the menu bar...
393 wxMenuBar
*menuBar
= new wxMenuBar();
394 menuBar
->Append(menuFile
, wxT("&File"));
395 menuBar
->Append(menuEvent
, wxT("&Event"));
397 // ... and attach this menu bar to the frame
402 SetStatusText(wxT("Welcome to wxWidgets event sample"));
403 SetStatusText(wxT("Dynamic: off"), Status_Dynamic
);
404 SetStatusText(wxT("Push count: 0"), Status_Push
);
405 #endif // wxUSE_STATUSBAR
407 wxPanel
* const panel
= new wxPanel(this);
408 wxSizer
* const mainSizer
= new wxBoxSizer(wxVERTICAL
);
409 wxSizer
* const sizer
= new wxBoxSizer(wxHORIZONTAL
);
410 const wxSizerFlags
centreY(wxSizerFlags().Centre().Border());
411 sizer
->Add(new wxStaticText(panel
, wxID_ANY
,
412 "This button will only work if its handler is dynamically connected"),
414 m_btnDynamic
= new wxButton(panel
, Event_Dynamic
, "&Dynamic button");
415 sizer
->Add(m_btnDynamic
, centreY
);
417 mainSizer
->Add(sizer
, 1, wxEXPAND
);
418 mainSizer
->Add(new wxStaticLine(panel
), 0, wxEXPAND
);
419 mainSizer
->Add(new wxStaticLine(panel
), 0, wxEXPAND
);
421 m_testBtn
= new MyEvtTestButton(panel
, "Test Event Handlers Execution Order");
423 // After being created, an instance of MyEvtTestButton already has its own
424 // event handlers (see class definition);
426 // Add a dynamic handler for this button event in the parent frame
427 Connect(m_testBtn
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
428 wxCommandEventHandler(MyFrame::OnClickDynamicHandlerFrame
));
430 // Bind a method of this frame (notice "this" argument!) to the button
432 m_testBtn
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
433 wxCommandEventHandler(MyFrame::OnClickDynamicHandlerButton
),
437 mainSizer
->Add(m_testBtn
);
438 panel
->SetSizer(mainSizer
);
443 // we must pop any remaining event handlers to avoid memory leaks and
445 while ( m_nPush
-- != 0 )
447 PopEventHandler(true /* delete handler */);
451 // ----------------------------------------------------------------------------
452 // standard event handlers
453 // ----------------------------------------------------------------------------
455 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
457 // true is to force the frame to close
461 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
463 wxMessageBox("Event sample shows different ways of using events\n"
464 "(c) 2001-2009 Vadim Zeitlin",
465 "About wxWidgets Event Sample",
466 wxOK
| wxICON_INFORMATION
, this);
469 void MyFrame::OnClickStaticHandlerFrame(wxCommandEvent
& event
)
471 wxLogMessage("Step 6, 4 in \"How Events are Processed\":\n"
472 "parentWin::StaticHandler_InFrameTable");
477 // ----------------------------------------------------------------------------
478 // dynamic event handling stuff
479 // ----------------------------------------------------------------------------
481 void MyFrame::OnClickDynamicHandlerFrame(wxCommandEvent
& event
)
483 wxLogMessage("Step 6, 3 in \"How Events are Processed\":\n"
484 "parentWin::DynamicHandler_InFrameTable");
489 void MyFrame::OnClickDynamicHandlerButton(wxCommandEvent
& event
)
491 wxLogMessage("Step 3 in \"How Events are Processed\":\n"
492 "parentWin::DynamicHandler_InButtonTable");
497 void MyFrame::OnDynamic(wxCommandEvent
& event
)
500 if ( event
.GetEventObject() == this )
501 origin
= "menu item";
502 else if ( event
.GetEventObject() == m_btnDynamic
)
505 origin
= "unknown event source";
509 "This message box is shown from the dynamically connected "
510 "event handler in response to event generated by " + origin
,
511 "wxWidgets Event Sample", wxOK
| wxICON_INFORMATION
, this
515 #ifdef wxHAS_EVENT_BIND
517 void MyFrame::OnBind(wxCommandEvent
& event
)
519 if ( event
.IsChecked() )
521 // as we bind directly to the button, there is no need to use an id
522 // here: the button will only ever get its own events
523 m_btnDynamic
->Bind(wxEVT_COMMAND_BUTTON_CLICKED
, &MyFrame::OnDynamic
,
526 // but we do need the id for the menu command as the frame gets all of
528 Bind(wxEVT_COMMAND_MENU_SELECTED
, &MyFrame::OnDynamic
, this,
533 m_btnDynamic
->Unbind(wxEVT_COMMAND_BUTTON_CLICKED
,
534 &MyFrame::OnDynamic
, this);
535 Unbind(wxEVT_COMMAND_MENU_SELECTED
, &MyFrame::OnDynamic
, this,
539 UpdateDynamicStatus(event
.IsChecked());
542 #endif // wxHAS_EVENT_BIND
544 void MyFrame::OnConnect(wxCommandEvent
& event
)
546 if ( event
.IsChecked() )
548 m_btnDynamic
->Connect(wxID_ANY
, wxEVT_COMMAND_BUTTON_CLICKED
,
549 wxCommandEventHandler(MyFrame::OnDynamic
),
551 Connect(Event_Dynamic
, wxEVT_COMMAND_MENU_SELECTED
,
552 wxCommandEventHandler(MyFrame::OnDynamic
));
556 m_btnDynamic
->Disconnect(wxID_ANY
, wxEVT_COMMAND_BUTTON_CLICKED
,
557 wxCommandEventHandler(MyFrame::OnDynamic
),
559 Disconnect(Event_Dynamic
, wxEVT_COMMAND_MENU_SELECTED
,
560 wxCommandEventHandler(MyFrame::OnDynamic
));
563 UpdateDynamicStatus(event
.IsChecked());
566 // ----------------------------------------------------------------------------
567 // push/pop event handlers support
568 // ----------------------------------------------------------------------------
570 void MyFrame::OnPushEventHandler(wxCommandEvent
& WXUNUSED(event
))
572 PushEventHandler(new MyEvtHandler(++m_nPush
));
575 SetStatusText(wxString::Format(wxT("Push count: %u"), m_nPush
), Status_Push
);
576 #endif // wxUSE_STATUSBAR
579 void MyFrame::OnPopEventHandler(wxCommandEvent
& WXUNUSED(event
))
581 wxCHECK_RET( m_nPush
, wxT("this command should be disabled!") );
583 PopEventHandler(true /* delete handler */);
587 SetStatusText(wxString::Format(wxT("Push count: %u"), m_nPush
), Status_Push
);
588 #endif // wxUSE_STATUSBAR
591 void MyFrame::OnTest(wxCommandEvent
& WXUNUSED(event
))
593 wxLogMessage(wxT("This is the test event handler in the main frame"));
596 void MyFrame::OnUpdateUIPop(wxUpdateUIEvent
& event
)
598 event
.Enable( m_nPush
> 0 );
601 // ----------------------------------------------------------------------------
602 // custom event methods
603 // ----------------------------------------------------------------------------
605 void MyFrame::OnFireCustom(wxCommandEvent
& WXUNUSED(event
))
607 wxCommandEvent
eventCustom(wxEVT_MY_CUSTOM_COMMAND
);
609 wxPostEvent(this, eventCustom
);
612 void MyFrame::OnProcessCustom(wxCommandEvent
& WXUNUSED(event
))
614 wxLogMessage(wxT("Got a custom event!"));