ChefZ -- 磨劍錄 (A Coder's Log)

慣看秋月春風 一壺濁酒喜相逢 古今多少事 皆賦談笑中
posts - 42, comments - 3, trackbacks - 0, articles - 6

wxWidgets 101 之 7 - 宏 (macros)

Posted on 2008-11-13 13:52 chefZ 阅读(522) 评论(0)  编辑 收藏 引用

借這篇來表示 (非我原文):

(色彩對應)

看程序中如下宏语句:
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[] = {
wxEventTableEntry(wxEVT_COMMAND_MENU_SELECTED, Minimal_Quit, wxID_ANY, MyFrame::OnQuit, NULL),
     wxEventTableEntry(wxEVT_COMMAND_MENU_SELECTED, Minimal_About, wxID_ANY, MyFrame::OnAbout, NULL),

wxEventTableEntry(wxEVT_NULL, 0, 0, 0, 0)
};

 


  
  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 );
}


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理