From:http://zetcode.com/tutorials/wxwidgetstutorial/events/

Events
    Events are integral part of every GUI application. All GUI applications are event-driven. An application reacts to different event types which are generated during it's life. Events are generated mainly by the user of an application. But they can be generated by other means as well. e.g. internet connection, window manager, timer. When the application starts a main loop is created. The application sits in the main loop and waits for the events to be generated. The main loop quits, when we exit the application.
 
Definitions
    Event is a piece of application-level information from the underlying framework, typically the GUI toolkit. Event loop is a programming construct that waits for and dispatches events or messages in a program. The event loop repeatedly looks for event to process them.A dispatcher is a process which maps events to event handlers. Event handlers are methods that react to events.
    Event object is an object associated with the event. It is usually a window.Event type is a unique event, that has been generated.
 
A simple event example
    The traditional way to work with events in wxWidgets is to use static event tables. This was influenced by the MFC. A more flexible and modern way is to use the Connect() method. Because this way is superior to event tables, I use it throughout the wxWidgets tutorial.
 
Event table
    In the next example, we show an example, where we use event tables.
 
button.h
#include <wx/wx.h>
 
class MyButton : public wxFrame
{
public:
    MyButton(const wxString & title);
    void OnQuit(wxCommandEvent & event);
private:
    DECLARE_EVENT_TABLE()
};
 
button.cpp
#include "button.h"
 
MyButton::MyButton(const wxString & title)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150))
{
    wxPanel * panel = new wxPanel(this, wxID_ANY);
    wxButton * button =
        new wxButton(panel, wxID_EXIT, wxT("Quit"), wxPoint(20, 20));
    
    Centre();
}
void MyButton::OnQuit(wxCommandEvent & WXUNUSED(event))
{
    Close(true);
}
 
BEGIN_EVENT_TABLE(MyButton, wxFrame)
    EVT_BUTTON(wxID_EXIT, MyButton::OnQuit)
END_EVENT_TABLE()
 
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
main.cpp
#include "main.h"
#include "button.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
    MyButton * button = new MyButton(wxT("Button"));
    button->Show(true);
    
    return true;
}
 
    In our example we create a simple button. By clicking on the button, we close the application.
 
private:
    DECLARE_EVENT_TABLE()
 
    In the header file, we declare an event table with the DECLARE_EVENT_TABLE() macro.
 
BEGIN_EVENT_TABLE(MyButton, wxFrame)
    EVT_BUTTON(wxID_EXIT, MyButton::OnQuit)
END_EVENT_TABLE()
 
    We implement an event table by mapping each event to the appropriate member function.
 
Example using Connect()
    We will talk about a move event. A move event holds information about move change events. A more event is generated, when we move a window to a new position. The class that represents the move event is wxMoveEvent. The wxEVT_MOVE is an event type.
 
move.h
#include <wx/wx.h>
 
class Move : public wxFrame
{
public:
    Move(const wxString & title);
    void OnMove(wxMoveEvent & event);
    wxStaticText * st1;
    wxStaticText * st2;
};
 
move.cpp
#include "move.h"
 
Move::Move(const wxString & title)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
    wxPanel * panel = new wxPanel(this, -1);
    
    st1 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 10));
    st2 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 30));
    
    Connect(wxEVT_MOVE, wxMouseEventHandler(Move::OnMove));
    
    Centre();
}
void Move::OnMove(wxMoveEvent & event)
{
    wxPoint size = event.GetPosition();
    st1->SetLabel(wxString::Format(wxT("x: %d"), size.x));
    st2->SetLabel(wxString::Format(wxT("y: %d"), size.y));
}
 
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
main.cpp
#include "main.h"
#include "move.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
    Move * move = new Move(wxT("Move event"));
    move->Show(true);
    
    return true;
}
 
    The example displays the current position of the window.
 
Connect(wxEVT_MOVE, wxMoveEventHandler(Move::OnMove));
 
    Here we connect a wxEVT_MOVE event type with the OnMove() method.
 
wxPoint size = event.GetPosition();
 
    The event parameter in the OnMove() method is an object specific to a particular event. In our case it is the instance of a wxMoveEvent class. This object holds information about the event. We can find out the current position by calling the GetPosition() method of the event.
 
Event propagation
    There are two types of events. Basic events and command events.
They differ in propagation. Event propagation is travelling 
of events from child widgets to parent widgets and grand parent 
widgets etc. Basic events do not propagate. Command events do 
propagate. For example wxCloseEvent is a basic event.
It does not make sense for this event to propagate to parent widgtet.
    By default, the event that is catched in a event handler stops propagating.
To continue propagation, we must call the Skip() method.
 
propagate.h
#include <wx/wx.h>
 
class Propagate : public wxFrame
{
public:
    Propagate(const wxString & title);
    void OnClick(wxCommandEvent & event);
};
 
class MyPanel : public wxPanel
{
public:
    MyPanel(wxFrame * frame, int id);
    void OnClick(wxCommandEvent & event);
};
 
class MyButton : wxButton
{
public:
    MyButton(MyPanel * panel, int id, const wxString & label);
    void OnClick(wxCommandEvent & event);
};
 
propagate.cpp
 
#include <iostream>
#include "propagate.h"
 
const int ID_BUTTON = 1;
 
Propagate::Propagate(const wxString & title)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
    MyPanel * panel = new MyPanel(this, -1);
    new MyButton(panel, ID_BUTTON, wxT("Ok"));
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLICKED, 
        wxCommandEventHandler(Propagate::OnClick));
    Centre();
}
void Propagate::OnClick(wxCommandEvent & event)
{
    std::cout << "event reached frame class" << std::endl;
    event.Skip();
}
MyPanel::MyPanel(wxFrame * frame, int id)
:wxPanel(frame, id)
{
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLIKCED, 
        wxCommandEventHandler(MyPanel::OnClick));
}
void MyPanel::OnClick(wxCommandEvent & event)
{
    std::cout << "" <<< std::endl;
    event.Skip();
}
MyButton::MyButton(MyPanel * mypanel, int id, const wxString & label)
:wxButton(mypanel, id, label, wxPoint(15, 15))
{
    Connect(ID_BUTTON, wxEVT_COMMAND_BUTTON_CLICKED, 
        wxCommandEventHandler(MyButton::OnClick));
}
void MyButton::OnClick(wxCommandEvent & event)
{
    std::cout << "event reached button class" << std::endl;
    event.Skip();
}
 
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
main.cpp
#include "main.h"
#include "propagate.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
    Propagate * prop = new Propagate(wxT("Propagate"));
    prop->Show(true);
    return true;
}
 
    In our example, we have a button on a panel. The panel is placed in a frame widget. We define a handler for all widgets.
 
event reached button class
event reached panel class
event reached frame class
 
    We get this, when we click on the button. The event travels from the button to panel and to frame. Try to omit some Skip() methods and see, what happens.
 
Vetoing events
 
    Sometimes we need to stop processing an event. To do this, we call the method Veto().
 
veto.h
#include <wx/wx.h>
 
class Veto : public wxFrame
{
public:
    Veto(const wxString & title);
    void OnClose(wxCloseEvent & event);
};
 
veto.cpp
#include "veto.h"
 
Veto::Veto(const wxString & title)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
    Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(Veto::OnClose));
    Centre();
}
void Veto::OnClose(wxCloseEvent & event)
{
    wxMessageDialog * dial = 
        new wxMessageDialog(NULL, wxT("Are you sure to quit?"), wxT("Question"), 
        wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
 
    int ret = dial->ShowModal();
    dial->Destroy();
 
    if(ret == wxID_YES)
        Destroy();
    else
        event.Veto();
}
 
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
main.cpp
#include "main.h"
#include "veto.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
    Veto * veto = new Veto(wxT("Veto"));
    veto->Show(true);
    return true;
}
 
    In our example, we process a wxCloseEvent. This event is called, when we click the X button on the titlebar, press Alt+F4 or select close from the system menu. In many applications, we want to prevent from accidentally closing the window, if we made some changes. To do this, we must connect the wxEVT_CLOSE_WINDOW event type.
 
wxMessageDialog * dial = new wxMessageDialog(NULL, 
    wxT("Are you sure to quit?"), wxT("Question"), 
    wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
 
    During the close event, we show a message dialog.
 
if(ret == wxID_YES)
    Destroy();
else
    event.Veto();
 
    Depending on the return value, we destroy the window, or veto the event. Notice that to close the window, we must call the Destroy() method. By calling the Close() method, we would end up in an endless cycle.
 
Window identifiers
    Window identifiers are integers that uniquely determine the window identity in the event system. There are three ways to create window id's.
 
    let the system automatically create an id
    use standard identifiers
    create your own id
 
    Each widget has an id parameter. This is an unique number in the event system.
If we work with multiple widgets, we must differantiate among them.
 
wxButton(parent, -1)
wxButton(panent, wxID_ANY)
 
    If we provide -1 or wxID_ANY for the id parameter, we let the wxWidgets automatically create an id for us. The automatically created id's are always negative, whereas user specified id's must always be positive. We usually use this option when we do not need to change the widget state. For example a static text, that will never be changed during the life of the application. We can still get the id, if we want. There is a method GetId(), which will determine the id for us. Standard identifiers should be used whenever possible. The identifiers can provide some standard graphics or behaviour on some platforms.
 
ident.h
#include <wx/wx.h>
 
class Ident : public wxFrame
{
public:
    Ident(const wxString & title);
};
 
ident.cpp
#include "ident.h"
 
Ident::Ident(const wxString & title)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(200, 150))
{
    wxPanel * panel = new wxPanel(this, -1);
    wxGridSizer * grid = new wxGridSizer(2, 3);
 
    grid->Add(new wxButton(panel, wxID_CANCEL), 0, wxTOP | wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_DELETE), 0, wxTOP, 9);
    grid->Add(new wxButton(panel, wxID_SAVE), 0, wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_EXIT));
    grid->Add(new wxButton(panel, wxID_STOP), 0, wxLEFT, 9);
    grid->Add(new wxButton(panel, wxID_NEW));
 
    panel->SetSizer(grid);
    Centre();
}
 
main.h
#include <wx/wx.h>
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
main.cpp
#include "main.h"
#include "ident.h"
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
    Ident * ident = new Ident(wxT("Identifiers"));
    ident->Show(true);
    return true;
}
 
    In our example we use standard identifiers on buttons. On Linux, the button have small icons.
    In this chapter, we talked about events in wxWidgets.
 
From:wxWindows 2 用C++编写跨平台程序
 
第三章 事件处理
 
目录
介绍
它是如何工作的
事件跳转
禁止事件
加挂事件句柄
 
介绍Introduction
    事件是出现在程序内部或外部的一些事情。一个事件可能是通过用户或是其他程序、操作系统等来触发的。这时需要一个机制来让程序员对期望的事件产生反应。
    在wxWindows的早期版本中,程序的事件处理是完全通过回调函数或者重载虚拟函数来实现的。从wxWindows 2.0开始转而使用事件表了。
 
例3.1 事件表
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_EXIT, MyFrame::OnExit)
    EVT_SIZE(MyFrame::OnSize)
    EVT_BUTTON(BUTTON1, MyFrame::OnButton1)
END_EVENT_TABLE()
 
    上面的事件表告诉wxWindows当它接收一个WM_SIZE事件时调用MyFrame的成员函数OnSize。宏BEGIN_EVENT_TABLE声明wxFrame和它的子类MyFrame拥有这个事件表。
    处理事件的成员函数不能是虚拟的。实际上事件处理将忽略虚拟声明。事件处理函数有类似的形式:返回类型为void并且接受一个事件参数。这个参数的类型与具体的事件相关。对于size事件,使用的类型是wxCommandEvent。当控件变的更复杂时它们使用自己的事件类。
    在类定义中,必须有一个DECLARE_EVENT_TABLE宏。
    所有这些宏隐藏了复杂的事件处理系统。
 
它是如何工作的?
    当接收一个事件时,wxWindows首先调用窗口上产生事件的对象上的wxEventHandler的ProcssEvent处理器。wxWindow(和其它的窗口类)继承自wxEventHander。ProcessEvent查找事件表里的每一个事件并且调用零或多个事件处理器函数。下面是处理一个事件的步骤:
    1、当对象关闭时(包括wxEvtHandler和SetEvtHandle)函数跳转到第六步。
    2、如果对象是一个wxWindow对象,ProcessEvent在窗口的wxValidator上递归调用。如果返回真函数退出。
    3、SearchEventTable是事件处理器调用的函数。当它失败时,开始在基类上尝试直到没有更多的事件表或者发现了一个合适的函数时这个函数退出。被发现的函数开始执行。
    4、查找过程应用于整个事件处理链,当应用成功时(表示事件处理完毕)函数退出。
    5、当对象是一个wxWindow对象时,并且事件为wxCommandEvent类型时,ProcessEvent向上递归应用于父窗口的事件处理器。当它返回真,函数退出。这可以让一个按钮的父亲来处理按钮点击而不是让按钮自己来处理。
    6、最后ProcessEvent在wxApp对象上调用。
 
事件跳转Event skipping
    ProcessEvent在发现一个可以处理事件的函数后退出。这表示当你的类对一个事件起反应时,下层的类不会得到这个事件。有时我们不希望这样。这个问题可以根据基类的事件类型用wxEvent类的Skip方法来解决,使事件处理器的查找继续进行。
 
例3.2 NumTextCtrl.h
class NumTextCtrl : public wxTextCtrl
{
public:
    NumTextCtrl(wxWindow * parent);
    void OnChar(wxKeyEvent & event);
protected:
    DECLARE_EVENT_TABLE()
};
 
    当NumbericTextCtrl接收到一个键盘事件后,就进行keycode检查。如果输入的是数字,基类wxTextCtrl就可以处理这个事件。这就是我们要对这个事件使用跳转的原因。你必须在这调用Skip方法,否则基类不会处理任何键。
 
例3.3 NumTextCtrl.cpp
// For compilers that supports precompilation, include "wx/wx.h"
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif
#include "NumTextCtrl.h"
#include <ctype.h>
NumTextCtrl::NumTextCtrl(wxWindow * parent)
:wxTextCtrl(parent, -1)
{}
void NumTextCtrl::OnChar(wxKeyEvent & event)
{
    if(isdigit(event.GetKeyCode()))
    {
        // Numeric characters are allowed, so the base class wxTextCtrl
        // is allowed to process the event. This is done using the Skip() 
        // method.
        event.Skip();
    }
    else
    {
        // Character is not allowed.
        wxBell();
    }
}

BEGIN_EVENT_TABLE(NumTextCtrl, wxTextCtrl)
    EVT_CHAR(NumTextCtrl::OnChar)
END_EVENT_TABLE()
 
禁止事件
    一些事件是可以禁止的。当你禁止一个事件时,这个事件不会被进一步处理。当一个文本控件内的文本改变后如何禁止这个简单文本编辑器的关闭事件。这表示当在用户还没有保存改变后的文本内容时这个窗口不能被关闭。
 
例3.4 禁止事件
void TextFrame::OnClose(wxCloseEvent & event)
{
    bool destroy = true;
    if(event.CanVeto())
    {
        if(m_pTextCtrl->IsModified())
        {
            wxMessageDialog * dlg = 
                new wxMessageDialog(
                this, 
                "Text is changed!\nAre you sure you want to exit?", 
                "Text changed!!!", 
                wxYES_NO | wxNO_DEFAULT);
            int result = dlg->ShowModal();
            if(result == wxID_NO)
            {
                event.Veto();
                destroy = false;
            }
        }
    }
    if(destroy)
    {
        Destroy();
    }    
}
 
    当CanVeto返回false时程序作什么呢?你将不能禁止这个事件你的程序将会退出。
 
阻塞事件处理器Plug an event handler
    考虑下面的问题:每个菜单命令都必须被记录。一个解决方案是创建一个在每个命令事件处理函数中调用的函数。这种方法带来的问题是使维护变得十分困难。当添加一个新的菜单并且没有调用这个函数时,这个菜单命令将不被记录。
    解决这个问题是去创建一个新的事件处理器并添加一个wxWindows类。要完成它需要创建一个从wxEvtHandler派生的新类。在新类中处理器与一个正常的窗口是相同的。
 
例3.5 LogEventHandler.h -LogEventHandler的定义
#ifndef _LogEventHandler_H
#define _LogEventHandler_H
class LogEventHandler : public wxEvtHandler
{
public:
    LogEventHandler()
    :wxEvtHandler()
    {}
    virtual ~LogEventHandler()
    {}
protected:
    DECLARE_EVENT_TABLE()
    void OnMenu(wxMenuEvent & event);
private:
};
#endif // _LogEventHandler_H
 
例3.6 LogEventHandler.cpp -LogEventHandler的实现
//For compilers that supports precompilation, include "wx/wx.h"
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif
#include "LogEventHandler.h"
void LogEventHandler::OnMenu(wxMenuEvent & event)
{
    wxLogMessage("Someone selected a menu item");
    event.Skip();
}

BEGIN_EVENT_TABLE(LogEventHandler, wxEvtHandler)
    EVT_MENU_RANGE(-1, -1, LogEventHandler::OnMenu)
END_EVENT_TABLE()
 
    在宏EVT_MENU_RANGE里,所有的菜单事件都可以被处理。前两个参数用来指定要处理的菜单的ID范围。-1表示处理所有的菜单项。不要忘记在事件上调用Skip,否则不会有任何事件传递到类wxWindow的事件处理器。
    下一步是把新的事件处理器压入处理栈。这是使用wxWindows的ushEventHandler来完成的。要从栈上移除事件处理器使用PopEventHandler。
 
PushEventHandler(new LogEventHandler());
 
    PopEventHandler有一个布尔类型的参数,当这个参数为真时,wxWindows删除事件处理器。注意在没有事件处理器被取出时,wxWindows将在窗口撤销时尝试删除事件处理器。这在访问在栈上创建的事件处理器时会发生一个访问错误。可以在一个类撤销之前调用使用false参数的PopeventHandler来避免这个问题。
 
From:http://www.cnblogs.com/alli/archive/2011/03/22/1991712.html
使用wxWidgets的事件机制进行线程间通信
 
    wxWidgets是个非常优秀的跨平台库,既可以用来开发GUI程序,也可以用来开发GUI程序,也可以用来开发事件驱动的无GUI服务器程序。wxWidgets的事件处理机制为线程间通信提供了又一个便利的方法。下面是具体步骤:
1、头文件中定义事件ID或直接使用wxID_ANY
#define ID_MY_THREAD_EVENT
2、主线程中定义事件处理函数
void OnMyThreadEvent(wxThreadEvent & event);
3、事件关联表中增加事件与处理函数的关联
BEGIN_EVENT_TABLE(MyApp, wxApp)
    EVT_THREAD(ID_MY_THREAD_EVENT, MyApp::OnMyThreadEvent)
END_EVENT_TABLE()
4、另一个线程发送事件
wxThreadEvent e(wxEVT_COMMAND_THREAD, ID_MY_THREAD_EVENT);
e.SetString(_T("Some string"));
wxTheApp->QueueEvent(e.Clone());
5、之前定义的事件处理函数中处理事件。