// * create by zyzx
// * 2009-3-16
// * 轉載請注明來源:http://www.shnenglu.com/zyzx
??????? 想了幾天,不知道如何動筆寫例程,網絡上關于wx框架例程也不多。入門最好先讀《Cross-Platform GUI Programming with wxWidgets_CN》(中文版)和wx庫本身自帶的說明文檔。
??????? 關于組件的使用,官方源代碼中提供了很多例程wxWidgets-2.8.7\samples。
??????? 回想我作為初學者時,或許走了一些彎路。剛開始當然是讀教程和官方說明文檔,再到手工編寫UI組件(熟悉基本的幾個,其他的在使用上是差不多的),最后是結合工具DialogBlocks編寫。wx庫本身還有很多值得挖掘的地方,比如其事件綁定方式、XRC界面配置文件、SIZER界面自動配置、還有國際化等等。
??????? 這里我就按手工編寫和借助工具分別寫一份例程,例程的編寫過程,就是熟悉庫本身過程。
??????? 第一份手工編寫的例程,我還是想借助于經典游戲《貪吃蛇》來實現。而第二份使用DialogBlocks來實現類似VS界面。
??????? 以前學習OpenGL時候,有經典的書在手,但總是沒有程序實踐感觀,因而覺得很空洞。但自從慢慢的研讀hehe關于OpenGL的系列的實例教程,再結合書籍才慢慢了解3D編程。況且,本人也對wx庫了解不是很全面,也只能從其局部應用出發。因此,本系列例程程序側重于代碼實現,在很多方面還有局限性。關于wx庫完整的結構還得參考其自帶的說明文檔。
??????? 第一例程簡短的程序分四個文件:SnakeApp.h、SnakeApp.cpp、SnakeFrame.h、SnakeFrame.cpp。本系列例程會在此基礎之上完成。
??????? SnakeApp類中定義應用程序啟動類,繼承于wxApp。
??????? SnakeFrame類定義主Frame,創建界面框架和其中的子窗口組件。
一、類SnakeApp頭文件定義:
?1
class
?SnakeApp:?
public
?wxApp
?2
{
?3
public
:
?4
????
//
*?定義動態創建類
?5
????DECLARE_CLASS(?SnakeApp?)
?6
????
//
*?定義事件處理宏
?7
????DECLARE_EVENT_TABLE()
?8
?9
public
:
10
????SnakeApp();
11
12
????
//
*?類初始化
13
????
void
?Init();
14
????
//
*?窗口初始化
15
????
virtual
?
bool
?OnInit();
16
????
//
*?退出
17
????
virtual
?
int
?OnExit();
18
19
public
:
20
????
//
*?獲取主Frame
21
????SnakeFrame
*
?GetMainFrame()
{?
return
?m_MainFrame;?}
22
23
protected
:
24
????SnakeFrame
*
?m_MainFrame;
25
}
;
26
27
//
*?定義全局wxGetApp(),返回&SnakeApp
28
//
*?可以在工程的任意地方使用。
29
DECLARE_APP(SnakeApp)
??????? wxApp是基于線程類有關的,一般應用程序將一個繼承wxApp的類作為入口類,再用IMPLEMENT_APP宏定義入口類(入口地址)。
??????? DECLARE_EVENT_TABLE宏靜態定義此類接收的事件處理,未編寫的事件按默認處理。
??????? OnInit中一般是程序運行之前的創建窗口、配置程序環境等操作。
??????? OnExit程序結束時,需要處理的操作。注意,wx庫正常窗口鏈,在默認的wxApp::OnExit()函數執行后,都會被自動析構掉,并不需要顯示的調用析構。如果正常的窗口鏈被破壞,需要做相應的特殊處理,比如混合使用MFC或WIN32的API,都有可能破壞正常的窗口鏈。
??????? DECLARE_APP宏定義本工程中可以使用到的全局函數wxGetApp(),返回為本類的引用。此全局函數即為溝通其他各個部分(比如主Frame->窗口->組件)的中間橋梁。
二、類SnakeApp實現文件:
?1
//
*?入口函數定義
?2
IMPLEMENT_APP(?SnakeApp?)
?3
?4
//
*?動態創建類
?5
IMPLEMENT_CLASS(?SnakeApp,?wxApp?)
?6
?7
//
*?掛接事件響應宏
?8
BEGIN_EVENT_TABLE(?SnakeApp,?wxApp?)
?9
END_EVENT_TABLE()
10
11
SnakeApp::SnakeApp()
12
{
13
????Init();
14
}
15
16
void
?SnakeApp::Init()
17
{
18
????m_MainFrame?
=
?NULL;
19
}
20
21
bool
?SnakeApp::OnInit()
22
{
23
????
//
*?加載能處理圖片類型驅動
24
#if
?wxUSE_XPM
25
????wxImage::AddHandler(
new
?wxXPMHandler);
26
#endif
27
#if
?wxUSE_LIBPNG
28
????wxImage::AddHandler(
new
?wxPNGHandler);
29
#endif
30
#if
?wxUSE_LIBJPEG
31
????wxImage::AddHandler(
new
?wxJPEGHandler);
32
#endif
33
#if
?wxUSE_GIF
34
????wxImage::AddHandler(
new
?wxGIFHandler);
35
#endif
36
37
????
//
?*?創建主Frame
38
????SnakeFrame
*
?mainWindow?
=
?
new
?SnakeFrame(?NULL?);
39
????SetTopWindow(?mainWindow?);
40
????mainWindow
->
Show(
true
);
41
42
????m_MainFrame?
=
?mainWindow;
43
????
return
?
true
;
44
}
45
46
int
?SnakeApp::OnExit()
47
{
48
????
return
?wxApp::OnExit();
49
}
??????? IMPLEMENT_CLASS宏回應頭文件中的宏定義DECLARE_CLASS。
??????? BEGIN_EVENT_TABLE、BEGIN_EVENT_TABLE:掛接事件宏。類似MFC中消息部分的處理。
??????? DECLARE_CLASS宏表示此類可以被動態創建,指可以在運行時創建。實質是使用wxClassInfo來標記工程中唯一的類,運行時可以使用wxClassInfo信息來創建該類。Wx庫中比較經典的應用是xrc文件中定義了一些窗口信息的文本標簽,而程序運行時根據這些信息創建出一系列的窗口。如果窗口類需要運行時創建,必須要使用DECLARE_CLASS宏。注意本工程只是定義了此宏,并沒有使用其動態創建特性。
??????? wxImage::AddHandler()函數給wxImage的全局靜態變量添加對應圖片處理格式的Handler。責任鏈模式在wx庫中有廣泛的使用,作為使用者只需要關注wxImage提供的方法,而圖片格式(*.jpg、*.png、*.gif等)由對應的Handler來處理。另一個使用比較經典的是窗口事件的分發。
??????? New SnakeFrame( NULL ) 以NULL 為父窗指針的類一般直接或間接繼承于wxTopLevelWindow,表示可以作為頂層窗口的類。
??????? SetTopWindow( mainWindow )設置頂層窗口。
三、SnakeFrame類頭文件

class
?SnakeFrame:?
public
?wxFrame

{
public
:
????DECLARE_CLASS(?SnakeFrame?)
????DECLARE_EVENT_TABLE()

public
:
????SnakeFrame(wxWindow
*
?parent);
????
virtual
?
~
SnakeFrame();

????
//
*?初始化類
????
void
?Init();
????
//
*?創建窗口框架組件
????
void
?CreateControls();
protected
:


protected
:
????
//
*?窗口分割條
????wxSplitterWindow
*
?m_SplitterWindow;
}
;
??????? 如上部分UI View 部分即我們Demo需要完成的界面樣子。
??????? CreateControls()函數中中創建主Frame中的子窗口。
??????? m_SplitterWindow本界面使用窗口分割條的方式將窗口分割成游戲區域和控制提示區域。
四、SnakeFrame類實現文件部分
IMPLEMENT_CLASS(?SnakeFrame,?wxFrame?)

BEGIN_EVENT_TABLE(?SnakeFrame,?wxFrame?)
END_EVENT_TABLE()

SnakeFrame::SnakeFrame(wxWindow
*
?parent)

{
????
//
*?初始化類,并使用基類wxFrame創建Frame,其參數詳細見wx文檔
????Init();
????wxFrame::Create(?parent,?SNAKEFRAME_ID,?SNAKEFRAME_TITLE,?SNAKEFRAME_POSITION,?SNAKEFRAME_SIZE,?SNAKEFRAME_STYLE?);
????CreateControls();
????Centre();
}
SnakeFrame::
~
SnakeFrame()

{
}
void
?SnakeFrame::Init()

{
????m_SplitterWindow?
=
?NULL;
}
void
?SnakeFrame::CreateControls()

{
????SnakeFrame
*
?frame?
=
?
this
;

????
//
*?創建窗口分割條
????
//
*?wxID_ANY?=?-1,表示此窗口不能通過其ID來查詢
????wxSplitterWindow
*
?splitterwnd?
=
?
new
?wxSplitterWindow(?frame?,?wxID_ANY,SNAKEFRAME_POSITION,?SNAKEFRAME_SIZE);

????
//
*?創建一個普通窗口
????wxWindow
*
?wnd1?
=
?
new
?wxWindow(?splitterwnd?,?wxID_ANY);
????
//
*?創建一個文本編輯窗口
????wxWindow
*
?wnd2?
=
?
new
?wxTextCtrl(?splitterwnd?,?wxID_ANY);

????
//
*?使用垂直分割方式,分成左右窗口
????splitterwnd
->
SplitVertically(?wnd1,?wnd2,?SNAKEFRAME_SPL?);
????
//
*?設置分隔條SashSize為0,可以阻止拖動分割條改變窗口大小
????splitterwnd
->
SetSashSize(?
0
?);

????m_SplitterWindow?
=
?splitterwnd;
}
??????? wxFrame::Create創建Frame窗口。Wx庫中界面窗口部分類都有兩種創建方式:一、直接使用構造函數直接創建;二、分兩步,第一步使用默認構造函數只初始化類,第二步才使用Create函數來創建窗口。
??????? wxSplitterWindow這里使用其將窗口分割成左右兩部分,并設定分割條大小為0,即防止用戶拖動分割條。這里暫時使用兩個標準窗口來代替,下一個章節將替換這里為我們自己的類。
五、編譯并執行
??????? 設置編譯環境并編譯得到如下界面。

??????? 如果有些部分沒有提到,那是前面章節有可能已經提到,請翻閱前面部分查詢。本系列從wx庫的編譯、配置、到demo的各個部分完成有比較強的依賴次序。
??????
工程文件下載