]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/event/event.cpp
Fix build with wxUSE_FFILE=0.
[wxWidgets.git] / samples / event / event.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: event.cpp
3// Purpose: wxWidgets sample demonstrating different event usage
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 31.01.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001-2009 Vadim Zeitlin
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx/wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27// for all others, include the necessary headers (this file is usually all you
28// need because it includes almost all "standard" wxWidgets headers)
29#ifndef WX_PRECOMP
30 #include "wx/wx.h"
31#endif
32
33#ifndef wxHAS_IMAGES_IN_RESOURCES
34 #include "../sample.xpm"
35#endif
36
37#include <wx/statline.h>
38#include <wx/log.h>
39
40// ----------------------------------------------------------------------------
41// event constants
42// ----------------------------------------------------------------------------
43
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)
46wxDEFINE_EVENT(wxEVT_MY_CUSTOM_COMMAND, wxCommandEvent);
47
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), \
53 (wxObject *) NULL \
54 ),
55
56// ----------------------------------------------------------------------------
57// private classes
58// ----------------------------------------------------------------------------
59
60// Define a new application type, each program should derive a class from wxApp
61class MyApp : public wxApp
62{
63public:
64 // override base class virtuals
65 // ----------------------------
66
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();
71
72 // these are regular event handlers used to highlight the events handling
73 // order
74 void OnClickDynamicHandlerApp(wxCommandEvent& event);
75 void OnClickStaticHandlerApp(wxCommandEvent& event);
76
77 // we override wxConsoleApp::FilterEvent used to highlight the events
78 // handling order
79 virtual int FilterEvent(wxEvent& event);
80
81private:
82 DECLARE_EVENT_TABLE()
83};
84
85// Define a custom button used to highlight the events handling order
86class MyEvtTestButton : public wxButton
87{
88public:
89 static long BUTTON_ID;
90
91 MyEvtTestButton(wxWindow *parent, const wxString& label)
92 : wxButton(parent, BUTTON_ID, label)
93 {
94 // Add a dynamic handler for this button event to button itself
95 Connect(wxEVT_BUTTON,
96 wxCommandEventHandler(MyEvtTestButton::OnClickDynamicHandler));
97 }
98
99private:
100 void OnClickDynamicHandler(wxCommandEvent& event)
101 {
102 wxLogMessage("Step 3 in \"How Events are Processed\":\n"
103 "Button::ownDynamicHandler");
104
105 event.Skip();
106 }
107
108 void OnClickStaticHandler(wxCommandEvent& event)
109 {
110 wxLogMessage("Step 4 in \"How Events are Processed\":\n"
111 "Button::ownStaticHandler");
112
113 event.Skip();
114 }
115
116 DECLARE_EVENT_TABLE()
117};
118
119long MyEvtTestButton::BUTTON_ID = wxNewId();
120
121// Define a new frame type: this is going to be our main frame
122class MyFrame : public wxFrame
123{
124public:
125 // ctor(s)
126 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
127 virtual ~MyFrame();
128
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);
139
140 void OnFireCustom(wxCommandEvent& event);
141 void OnProcessCustom(wxCommandEvent& event);
142
143 void OnUpdateUIPop(wxUpdateUIEvent& event);
144
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);
149
150private:
151 // symbolic names for the status bar fields
152 enum
153 {
154 Status_Main = 0,
155 Status_Dynamic,
156 Status_Push
157 };
158
159 void UpdateDynamicStatus(bool on)
160 {
161#if wxUSE_STATUSBAR
162 if ( on )
163 {
164 SetStatusText("You can now use \"Dynamic\" item in the menu");
165 SetStatusText("Dynamic: on", Status_Dynamic);
166 }
167 else
168 {
169 SetStatusText("You can no more use \"Dynamic\" item in the menu");
170 SetStatusText("Dynamic: off", Status_Dynamic);
171 }
172#endif // wxUSE_STATUSBAR
173 }
174
175 // number of pushed event handlers
176 unsigned m_nPush;
177
178 // the button to whose event we connect dynamically
179 wxButton *m_btnDynamic;
180
181 // the button used to highlight the event handlers execution order
182 MyEvtTestButton *m_testBtn;
183
184
185 // any class wishing to process wxWidgets events must use this macro
186 DECLARE_EVENT_TABLE()
187};
188
189// Define a custom event handler
190class MyEvtHandler : public wxEvtHandler
191{
192public:
193 MyEvtHandler(size_t level) { m_level = level; }
194
195 void OnTest(wxCommandEvent& event)
196 {
197 wxLogMessage(wxT("This is the pushed test event handler #%u"), m_level);
198
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
201 event.Skip();
202 }
203
204private:
205 unsigned m_level;
206
207 DECLARE_EVENT_TABLE()
208};
209
210// ----------------------------------------------------------------------------
211// constants
212// ----------------------------------------------------------------------------
213
214// IDs for the controls and the menu commands
215enum
216{
217 // menu items
218 Event_Quit = 1,
219 Event_About,
220 Event_Bind,
221 Event_Connect,
222 Event_Dynamic,
223 Event_Push,
224 Event_Pop,
225 Event_Custom,
226 Event_Test
227};
228
229// ----------------------------------------------------------------------------
230// event tables and other macros for wxWidgets
231// ----------------------------------------------------------------------------
232
233// The event tables connect the wxWidgets events with the functions (event
234// handlers) which process them.
235BEGIN_EVENT_TABLE(MyApp, wxApp)
236 // Add a static handler for button Click event in the app
237 EVT_BUTTON(MyEvtTestButton::BUTTON_ID, MyApp::OnClickStaticHandlerApp)
238END_EVENT_TABLE()
239
240BEGIN_EVENT_TABLE(MyEvtTestButton, wxButton)
241 // Add a static handler to this button itself for its own event
242 EVT_BUTTON(BUTTON_ID, MyEvtTestButton::OnClickStaticHandler)
243END_EVENT_TABLE()
244
245// This can be also done at run-time, but for the
246// simple menu events like this the static method is much simpler.
247BEGIN_EVENT_TABLE(MyFrame, wxFrame)
248 EVT_MENU(Event_Quit, MyFrame::OnQuit)
249 EVT_MENU(Event_About, MyFrame::OnAbout)
250
251#ifdef wxHAS_EVENT_BIND
252 EVT_MENU(Event_Bind, MyFrame::OnBind)
253#endif // wxHAS_EVENT_BIND
254 EVT_MENU(Event_Connect, MyFrame::OnConnect)
255
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)
260
261 EVT_UPDATE_UI(Event_Pop, MyFrame::OnUpdateUIPop)
262
263 EVT_MY_CUSTOM_COMMAND(wxID_ANY, MyFrame::OnProcessCustom)
264
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)
268
269 // Add a static handler in the parent frame for button event
270 EVT_BUTTON(MyEvtTestButton::BUTTON_ID, MyFrame::OnClickStaticHandlerFrame)
271END_EVENT_TABLE()
272
273BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler)
274 EVT_MENU(Event_Test, MyEvtHandler::OnTest)
275END_EVENT_TABLE()
276
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
281// not wxApp)
282IMPLEMENT_APP(MyApp)
283
284// ============================================================================
285// implementation
286// ============================================================================
287
288// ----------------------------------------------------------------------------
289// the application class
290// ----------------------------------------------------------------------------
291
292// 'Main program' equivalent: the program execution "starts" here
293bool MyApp::OnInit()
294{
295 if ( !wxApp::OnInit() )
296 return false;
297
298 // create the main application window
299 MyFrame *frame = new MyFrame(wxT("Event wxWidgets Sample"),
300 wxPoint(50, 50), wxSize(600, 340));
301
302 // and show it (the frames, unlike simple controls, are not shown when
303 // created initially)
304 frame->Show(true);
305
306 // Add a dynamic handler at the application level for the test button
307 Connect(MyEvtTestButton::BUTTON_ID, wxEVT_BUTTON,
308 wxCommandEventHandler(MyApp::OnClickDynamicHandlerApp));
309
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.
313 return true;
314}
315
316// This is always the first to handle an event !
317int MyApp::FilterEvent(wxEvent& event)
318{
319 if ( event.GetEventType() == wxEVT_BUTTON &&
320 event.GetId() == MyEvtTestButton::BUTTON_ID )
321 {
322 wxLogMessage("Step 0 in \"How Events are Processed\":\n"
323 "App::FilterEvent");
324 }
325
326 return wxApp::FilterEvent(event);
327}
328
329void MyApp::OnClickDynamicHandlerApp(wxCommandEvent& event)
330{
331 wxLogMessage("Step 7, 3 in \"How Events are Processed\":\n"
332 "App::DynamicHandler_InAppTable");
333
334 event.Skip();
335}
336
337void MyApp::OnClickStaticHandlerApp(wxCommandEvent& event)
338{
339 wxLogMessage("Step 7, 4 in \"How Events are Processed\":\n"
340 "App::StaticHandler_InAppTable");
341
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 "
345 "were executed.");
346 wxLog::FlushActive();
347
348 event.Skip();
349}
350
351// ----------------------------------------------------------------------------
352// main frame
353// ----------------------------------------------------------------------------
354
355// frame constructor
356MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
357 : wxFrame(NULL, wxID_ANY, title, pos, size)
358{
359 SetIcon(wxICON(sample));
360
361 // init members
362 m_nPush = 0;
363 m_btnDynamic = NULL;
364
365 // create a menu bar
366 wxMenu *menuFile = new wxMenu;
367
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"));
371
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"));
391
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"));
396
397 // ... and attach this menu bar to the frame
398 SetMenuBar(menuBar);
399
400#if wxUSE_STATUSBAR
401 CreateStatusBar(3);
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
406
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"),
413 centreY);
414 m_btnDynamic = new wxButton(panel, Event_Dynamic, "&Dynamic button");
415 sizer->Add(m_btnDynamic, centreY);
416
417 mainSizer->Add(sizer, 1, wxEXPAND);
418 mainSizer->Add(new wxStaticLine(panel), 0, wxEXPAND);
419 mainSizer->Add(new wxStaticLine(panel), 0, wxEXPAND);
420
421 m_testBtn = new MyEvtTestButton(panel, "Test Event Handlers Execution Order");
422
423 // After being created, an instance of MyEvtTestButton already has its own
424 // event handlers (see class definition);
425
426 // Add a dynamic handler for this button event in the parent frame
427 Connect(m_testBtn->GetId(), wxEVT_BUTTON,
428 wxCommandEventHandler(MyFrame::OnClickDynamicHandlerFrame));
429
430 // Bind a method of this frame (notice "this" argument!) to the button
431 // itself
432 m_testBtn->Connect(wxEVT_BUTTON,
433 wxCommandEventHandler(MyFrame::OnClickDynamicHandlerButton),
434 NULL,
435 this);
436
437 mainSizer->Add(m_testBtn);
438 panel->SetSizer(mainSizer);
439}
440
441MyFrame::~MyFrame()
442{
443 // we must pop any remaining event handlers to avoid memory leaks and
444 // crashes!
445 while ( m_nPush-- != 0 )
446 {
447 PopEventHandler(true /* delete handler */);
448 }
449}
450
451// ----------------------------------------------------------------------------
452// standard event handlers
453// ----------------------------------------------------------------------------
454
455void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
456{
457 // true is to force the frame to close
458 Close(true);
459}
460
461void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
462{
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);
467}
468
469void MyFrame::OnClickStaticHandlerFrame(wxCommandEvent& event)
470{
471 wxLogMessage("Step 6, 4 in \"How Events are Processed\":\n"
472 "parentWin::StaticHandler_InFrameTable");
473
474 event.Skip();
475}
476
477// ----------------------------------------------------------------------------
478// dynamic event handling stuff
479// ----------------------------------------------------------------------------
480
481void MyFrame::OnClickDynamicHandlerFrame(wxCommandEvent& event)
482{
483 wxLogMessage("Step 6, 3 in \"How Events are Processed\":\n"
484 "parentWin::DynamicHandler_InFrameTable");
485
486 event.Skip();
487}
488
489void MyFrame::OnClickDynamicHandlerButton(wxCommandEvent& event)
490{
491 wxLogMessage("Step 3 in \"How Events are Processed\":\n"
492 "parentWin::DynamicHandler_InButtonTable");
493
494 event.Skip();
495}
496
497void MyFrame::OnDynamic(wxCommandEvent& event)
498{
499 wxString origin;
500 if ( event.GetEventObject() == this )
501 origin = "menu item";
502 else if ( event.GetEventObject() == m_btnDynamic )
503 origin = "button";
504 else
505 origin = "unknown event source";
506
507 wxMessageBox
508 (
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
512 );
513}
514
515#ifdef wxHAS_EVENT_BIND
516
517void MyFrame::OnBind(wxCommandEvent& event)
518{
519 if ( event.IsChecked() )
520 {
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_BUTTON, &MyFrame::OnDynamic,
524 this);
525
526 // but we do need the id for the menu command as the frame gets all of
527 // them
528 Bind(wxEVT_MENU, &MyFrame::OnDynamic, this,
529 Event_Dynamic);
530 }
531 else // disconnect
532 {
533 m_btnDynamic->Unbind(wxEVT_BUTTON,
534 &MyFrame::OnDynamic, this);
535 Unbind(wxEVT_MENU, &MyFrame::OnDynamic, this,
536 Event_Dynamic);
537 }
538
539 UpdateDynamicStatus(event.IsChecked());
540}
541
542#endif // wxHAS_EVENT_BIND
543
544void MyFrame::OnConnect(wxCommandEvent& event)
545{
546 if ( event.IsChecked() )
547 {
548 m_btnDynamic->Connect(wxID_ANY, wxEVT_BUTTON,
549 wxCommandEventHandler(MyFrame::OnDynamic),
550 NULL, this);
551 Connect(Event_Dynamic, wxEVT_MENU,
552 wxCommandEventHandler(MyFrame::OnDynamic));
553 }
554 else // disconnect
555 {
556 m_btnDynamic->Disconnect(wxID_ANY, wxEVT_BUTTON,
557 wxCommandEventHandler(MyFrame::OnDynamic),
558 NULL, this);
559 Disconnect(Event_Dynamic, wxEVT_MENU,
560 wxCommandEventHandler(MyFrame::OnDynamic));
561 }
562
563 UpdateDynamicStatus(event.IsChecked());
564}
565
566// ----------------------------------------------------------------------------
567// push/pop event handlers support
568// ----------------------------------------------------------------------------
569
570void MyFrame::OnPushEventHandler(wxCommandEvent& WXUNUSED(event))
571{
572 PushEventHandler(new MyEvtHandler(++m_nPush));
573
574#if wxUSE_STATUSBAR
575 SetStatusText(wxString::Format(wxT("Push count: %u"), m_nPush), Status_Push);
576#endif // wxUSE_STATUSBAR
577}
578
579void MyFrame::OnPopEventHandler(wxCommandEvent& WXUNUSED(event))
580{
581 wxCHECK_RET( m_nPush, wxT("this command should be disabled!") );
582
583 PopEventHandler(true /* delete handler */);
584 m_nPush--;
585
586#if wxUSE_STATUSBAR
587 SetStatusText(wxString::Format(wxT("Push count: %u"), m_nPush), Status_Push);
588#endif // wxUSE_STATUSBAR
589}
590
591void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
592{
593 wxLogMessage(wxT("This is the test event handler in the main frame"));
594}
595
596void MyFrame::OnUpdateUIPop(wxUpdateUIEvent& event)
597{
598 event.Enable( m_nPush > 0 );
599}
600
601// ----------------------------------------------------------------------------
602// custom event methods
603// ----------------------------------------------------------------------------
604
605void MyFrame::OnFireCustom(wxCommandEvent& WXUNUSED(event))
606{
607 wxCommandEvent eventCustom(wxEVT_MY_CUSTOM_COMMAND);
608
609 wxPostEvent(this, eventCustom);
610}
611
612void MyFrame::OnProcessCustom(wxCommandEvent& WXUNUSED(event))
613{
614 wxLogMessage(wxT("Got a custom event!"));
615}
616