借這篇來表示 (非我原文):
(色彩對應)
看程序中如下宏语句:
enum
{
Minimal_Quit = wxID_EXIT,
Minimal_About = wxID_ABOUT
};
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Minimal_Quit, MyFrame::OnQuit)
EVT_MENU(Minimal_About, MyFrame::OnAbout)
END_EVENT_TABLE()
IMPLEMENT_APP(MyApp)
现在展开这些宏来分析内部的运行机制
1. 展开BEGIN_EVENT_TABLE(MyFrame, wxFrame)
2. 展开EVT_MENU(Minimal_Quit, MyFrame::OnQuit)
3. 展开END_EVENT_TABLE()
1. 在wxWidgets-2.6.2\include\wx\event.h文件中宏 BEGIN_EVENT_TABLE 被定义如下:
#define BEGIN_EVENT_TABLE(theClass, baseClass)
¨ const wxEventTable theClass::sm_eventTable = { &baseClass::sm_eventTable, theClass::sm_eventTableEntries[0] }; ¨ const wxEventTable *theClass::GetEventTable() const { return &theClass::sm_eventTable; } ¨ wxEventHashTable theClass::sm_eventHashTable(theClass::sm_eventTable); ¨ wxEventHashTable &theClass::GetEventHashTable() const { return theClass::sm_eventHashTable; } ¨ const wxEventTableEntry theClass::sm_eventTableEntries[] = {
|
经过预编译处理后程序如下:
¨ const wxEventTable MyFrame::sm_eventTable = { &wxFrame::sm_eventTable, &MyFrame::sm_eventTableEntries[0] }; ¨ const wxEventTable *MyFrame::GetEventTable() const { return &MyFrame::sm_eventTable; } ¨ wxEventHashTable MyFrame::sm_eventHashTable(MyFrame::sm_eventTable); ¨ wxEventHashTable &MyFrame::GetEventHashTable() const { return MyFrame::sm_eventHashTable; } ¨ const wxEventTableEntry MyFrame::sm_eventTableEntries[] = {
|
2. 在wxWidgets-2.6.2\include\wx\event.h 文件中宏 EVT_MENU 被定义如下:
#define EVT_MENU(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_MENU_SELECTED, winid, wxCommandEventHandler(func)) #define wx__DECLARE_EVT1(winid, id, func) wx__DECLARE_EVT2(winid, id, wxID_ANY, func) #define wx__DECLARE_EVT2(winid, id1, id2, func) DECLARE_EVENT_TABLE_ENTRY(winid, id1, id2, func, NULL), #define DECLARE_EVENT_TABLE_ENTRY(type, winid, idLast, func, obj) wxEventTableEntry(type, winid, idLast, func, obj)
|
当中 wxCommandEventHandler(func) 进行静态强制类型转化,把指定的函数 (func) 指针类型转化为事件处理函数类型
#define wxCommandEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxCommandEventFunction, &func) : (wxObjectEventFunction*)(wxEventFunction*)(wxCommandEventFunction*)&func(wxCommandEvent&) : (wxObjectEventFunction*)(wxEventFunction*)(wxCommandEventFunction*)(*func)((wxCommandEvent&)&winid)
|
注:
typedef void (wxObject::*wxObjectEventFunction)(wxEvent&);
typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
typedef void (wxEvtHandler::*wxCommandEventFunction)(wxCommandEvent&);
#define wxStaticCastEvent(type, val) wx_static_cast(type, val)
#define wx_static_cast(t, x) ((t)(x)) //进行强制类型转化 (C type cast)
e.g
EVT_MENU(Minimal_Quit, MyFrame::OnQuit) 经过预编译处理后程序如下:
#define EVT_MENU(Minimal_Quit, MyFrame::OnQuit) wx__DECLARE_EVT1(wxEVT_COMMAND_MENU_SELECTED, Minimal_Quit, wxCommandEventHandler(MyFrame::OnQuit)) #define wx__DECLARE_EVT1(evt, id, MyFrame::OnQuit) wx__DECLARE_EVT2(evt, id, wxID_ANY, MyFrame::OnQuit) #define wx__DECLARE_EVT2(evt, id1, id2, MyFrame::OnQuit) DECLARE_EVENT_TABLE_ENTRY(evt, id1, id2, MyFrame::OnQuit, NULL), #define DECLARE_EVENT_TABLE_ENTRY(type, Minimal_Quit, idLast, MyFrame::OnQuit, obj) wxEventTableEntry(type, Minimal_Quit, idLast, MyFrame::OnQuit, obj)
|
Type = wxEVT_COMMAND_MENU_SELECTED
idLast = wxID_ANY
obj = NULL
wxEventTableEntry(wxEVT_COMMAND_MENU_SELECTED, Minimal_Quit, wxID_ANY, MyFrame::OnQuit, NULL)
3. 在wxWidgets-2.6.2\include\wx\event.h 文件中宏 BEGIN_EVENT_TABLE 被定义如下:
#define END_EVENT_TABLE() DECLARE_EVENT_TABLE_ENTRY( wxEVT_NULL, 0, 0, 0, 0 ) };
再展开DECLARE_EVENT_TABLE_ENTRY:
#define DECLARE_EVENT_TABLE_ENTRY(type, winid, idLast, fn, obj) wxEventTableEntry(type, winid, idLast, fn, obj)
经过预编译处理后程序如下:
Type = wxEVT_NULL
idLast = NULL
obj = NULL
wxEventTableEntry(wxEVT_NULL, 0, 0, 0, 0)};
综合上面所述,
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Minimal_Quit, MyFrame::OnQuit)
EVT_MENU(Minimal_About, MyFrame::OnAbout)
END_EVENT_TABLE()
最终展开的效果为:
¨ const wxEventTable MyFrame::sm_eventTable = { &wxFrame::sm_eventTable, &MyFrame::sm_eventTableEntries[0] }; ¨ const wxEventTable *MyFrame::GetEventTable() const { return &MyFrame::sm_eventTable; } ¨ wxEventHashTable MyFrame::sm_eventHashTable(MyFrame::sm_eventTable); ¨ wxEventHashTable &MyFrame::GetEventHashTable() const { return MyFrame::sm_eventHashTable; } ¨ const wxEventTableEntry MyFrame::sm_eventTableEntries[] = { |
wxWidgets 通过宏的方式在预编译时静态设置好了事件映射表, 把指定的一个唯一的命令 ID 和 MyFrame 的指定函数静态绑定。实际上也可以进行动态绑定,这里先不描述。
IMPLEMENT_APP(MyApp)宏展开如下:
IMPLEMENT_APP(appname)
l IMPLEMENT_APP_NO_THEMES(appname)
n IMPLEMENT_APP_NO_MAIN(appname)
wxAppConsole *wxCreateApp()
{
wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "your program name");
return new appname;
}
wxAppInitializer wxTheAppInitializer((wxAppInitializerFunction) wxCreateApp);
appname & wxGetApp()
{
return *( appname *)wxTheApp;
}
n IMPLEMENT_WXWIN_MAIN
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wxCmdLineArgType lpCmdLine, int nCmdShow)
{
return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
l IMPLEMENT_WX_THEME_SUPPORT
最终的结果为:
wxAppConsole *wxCreateApp()
{
wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "your program name");
return new MyApp;
}
wxAppInitializer
wxTheAppInitializer((wxAppInitializerFunction) wxCreateApp);
MyApp& wxGetApp()
{
return *( MyApp*)wxTheApp;
}
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wxCmdLineArgType lpCmdLine, int nCmdShow)
{
return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
可以看出这个就是win32应用程序主程序了。它通过 wxEntry 函数实现整个主函数的功能,该函数与平台相关,可以自己调用本函数实现 wxWidgets 默认的入口函数 (参考 manual)。该函数的实现在 wxWidgets-2.6.2\src\msw\main.cpp。
程序继续执行,在函数 int wxEntryReal(int& argc, wxChar **argv) 内部主要完成三个事情:
1: 调用 wxApp::Initialize 初始化应用程序,初始化时候调用 wxApp::RegisterWindowClasses() 注册一个窗口类, 注册窗口类后, wxWidgets-2.6.2\src\msw\window.cpp文件下的 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 成为窗口事件处理主函数,负责窗口事件处理。后面创建 MyFrame 时候最终会调用 CreateWindow 创建函数主窗口。
2: 调用 wxAppConsole::CallOnInit(),该函数最后调用 bool MyApp::OnInit() 虚拟函数初始化应用程序,因此经过 wxWidgets 封装后,呈现给用户的最终的主程序入口就是用户自己重载的 OnInit() 虚拟函数。在 MyFrame 构造函数调用wxTopLevelWindow::Create() 完成窗口创建。
3: 最后调用 wxAppBase::OnRun() 进行消息循环接收发送, 把属于窗口的消息发送给 wxWndProc 进行处理。
Example: Customized Event & Event Macro (given in http://docs.wxwidgets.org/2.6.3/wx_eventhandlingoverview.html#eventmacros)
// code defining event
class wxPlotEvent: public wxNotifyEvent
{
public:
wxPlotEvent( wxEventType commandType = wxEVT_NULL, int id = 0 );
// accessors
wxPlotCurve *GetCurve()
{ return m_curve; }
// required for sending with wxPostEvent()
wxEvent* Clone();
private:
wxPlotCurve *m_curve;
};
DECLARE_EVENT_MACRO( wxEVT_PLOT_ACTION, -1 )
typedef void (wxEvtHandler::*wxPlotEventFunction)(wxPlotEvent&);
#define EVT_PLOT(id, fn) \
DECLARE_EVENT_TABLE_ENTRY( wxEVT_PLOT_ACTION, id, -1, \
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \
wxStaticCastEvent( wxPlotEventFunction, & fn ), (wxObject *) NULL ),
// code implementing the event type and the event class
DEFINE_EVENT_TYPE( wxEVT_PLOT_ACTION )
wxPlotEvent::wxPlotEvent( ...
// user code intercepting the event
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_PLOT(ID_MY_WINDOW, MyFrame::OnPlot)
END_EVENT_TABLE()
void MyFrame::OnPlot( wxPlotEvent &event )
{
wxPlotCurve *curve = event.GetCurve();
}
// user code sending the event
void MyWindow::SendEvent()
{
wxPlotEvent event( wxEVT_PLOT_ACTION, GetId() );
event.SetEventObject( this );
event.SetCurve( m_curve );
GetEventHandler()->ProcessEvent( event );
}