wxWidgets

開源的跨平台的C++構架庫

wxWidgets是一個開源的跨平台的C++構架庫(framework),它可以提供GUI(圖形用戶界面)和其它工具。目前的2.x版本支持所有版本的Windows、帶GTK+或Motif的Unix和MacOS。一個支持OS/2的版本正在開發中。

起源


wxWidgets在最開始是由愛丁堡(Edinburgh)大學的人工智慧應用學院開發的,主要是內部使用,而在1992年第一次公布。 2.x版本做了很大程度的改良,並且由Julian Smart, Robert Roebling, Vadim Zeitlin, Vaclav Slavik和更多其他的人所編寫和維護。
wxWidgets的主體是由C++構建的,但你並不是必需通過C++才能使用wxWidgets.wxWidgets擁有許多其它語言的綁定(binding),使你在用其它語言編寫程序的時候也可以使用wxWidgets.
* wxPython a Python binding,
* wxPerl a Perl binding,
* wxBasic a Basic binding,
* wxLua a Lua binding,
* wxJavaScript a JavaScript binding,
* wxJava a Java binding by Steve Perkins,
* wx4j a Java binding by Dave Dribin,
* wxRuby a Ruby binding,
* wxEiffel an Eiffel binding,
* wxHaskell a Haskell binding,
* wxEuphoria a Euphoria binding,
* wxAda the start of an Ada binding for wxWidgets.
wxwidgets是一個 c++編寫的用來提供gui開發的框架。它包含一個可以支持現今幾乎所有操作系統(Version 2 currently supports all desktop versions of MS Windows, Unix with GTK+, Unix with Motif, and MacOS. An OS/2 port is in progress.)的GUI庫和其他一些很有用的工具,提供了類似MFC的功能。而且,特別要說一下,這個c++lib的新版本還提供了對掌上電腦的支持。當然,說到這裡很多人會想到java對多系統的支持,其實這是不一樣的,java的跨平台是建立在“中間代碼”的基礎上的,就是說需要在目標平台上安裝java解釋器;但是wxwidgets是c++庫,經過編譯后,他提供的是native級的機器碼,在gui編程方面,這可是意味著很大的不同。

優勢


那麼wxwidgets有什麼特別之處呢?比起其他的跨平台gui庫,有什麼好處呢?
1、就是他無論對於個人還是對於商業應用都是免費的!
——它的主體框架的授權協議支持商業免費應用,其外圍功能庫中很多也是lgpl授權的,這無疑對於我等“0資本”的人來說是天大的好事。不同於Qt之類的跨平台gui庫。
2、他是跨平台的gui庫,支持的操作系統很全面,甚至支持pda(最新版本【3.0.1】支持iOS,可以在下載的源碼包中找到wxWidgets-3.0.1.tar.bz2\wxWidgets-3.0.1\build\osx\wxiphone.xcodeproj)。
—— 此跨平台非彼跨平台,它雖然不像java那樣是“全面”的,而僅僅是gui庫,但是gui是計算機編程中,最為麻煩、耗費時間、容易出現bug的部分,特別當你想要自己的軟體運行在多個操作系統上的時候,開發和維護的難度讓人難以想象。其實c++也是支持“跨平台”的,因為c++可以在任何平台上編譯運行,之所以沒幾個人說他是跨平台的,主要問題就出在變數長度和各操作系統的gui(這裡的“界面”我指得是很廣義的)上,如果解決了gui的問題,基本上就解決了c++的“跨平台”問題——至少不用為每種平台都維護一份源代碼了。
3、 wxwidgets提供的gui是大量使用宏的,這就意味著它是在儘可能的使用目標系統native的gui樣式。
——你可以訪問wxwidgets網站,看看那些開發的軟體的截圖,全是系統native級別的。如果你開發了一個xp系統的軟體的話,你的軟體會仍然以“xp專有的‘小賤人’級別”的面貌展現在你面前。
4、它支持的編譯器也很多,而且borland也曾聲明將在c++builderx2裡邊提供對wxidgets的支持——預覽版都出來了。
——其實我就是看到borland在c++不景氣的時候,這麼看重這個東東,甚至用它來做“王牌”,才開始注意到他的。當然,反過來,也正是borland的支持,才使他活力大發的。
5、自然,有牛X支持,而且是開源的,wxWidgets一直都在快速穩健的開發中,其周邊工具也越來越多。
—— 隨著MS開始全力支持他的.net,c++成了“沒落”的語言,但是不可否認,c++還是有很多用武之地的,所以根本不可能真正沒落。沒有了超牛X的支持,地球人自然開始尋求新的發展方式,wxWidgets這種開源免費,且允許商業應用的好東東,自然會被人們所重視。

事件處理機制


類似於MFC的MESSAGE_MAP,wxWidgets使用EVENT_TABLE語法糖實現對事件處理函數的回調。具體的實現方法是,在h文件的類聲明裡添加宏
wxDECLARE_EVENT_TABLE()
並在cpp文件裡面添加對應事件處理函數的列表:
wxBEGIN_EVENT_TABLE(..., ...)
EVT_MENU(..., ...)//菜單事件
EVT_BTN(..., ...)//按鈕事件
EVT_PAINT(...)//繪圖事件
EVT_LBUTTON_DOWN(...)//滑鼠事件
EVT_KEY_DOWN(...)//鍵盤事件
......
wxEND_EVENT_TABLE()
其中宏wxDECLARE_EVENT_TABLE()有兩個參數,第一個是自定義的類名,第二個是派生類的基類名。而裡面事件處理函數的列表中,不同的處理事件對應的宏參數不同。通常情況下,像菜單、按鈕這樣可能由不同控制項觸發的事件,對應的宏有兩個參數,第一個參數為控制項的ID,第二個參數為事件處理函數的指針。而像繪圖,滑鼠,鍵盤這樣的可以由不同硬體觸發或者觸發來源單一的事件,則有一個參數,即為事件處理函數的指針。

程序結構


wxWidgets程序封裝了main函數和消息循環。通常情況下,整個程序通過繼承wxApp類並用全局宏wxIMPLEMENT_APP,傳入wxApp的派生類的類名實現對類的實例化並進入消息循環。
在進入消息循環之前,創建主窗口的工作通過在wxApp的派生類中重新實現wxApp的虛函數OnInit來完成。主窗口通常是wxFrame或wxDialog的派生類,其中的控制項都作為主窗口類的成員變數,在主窗口類的構造函數中初始化。
從中可以看出,wxWidgets在程序結構方面與MFC也有很大的相似之處。

前景


當然,wxWidgets也有一些不足,比如官方文檔不全,對STL的支持不夠,特別是沒有源代碼的開發速度快;沒有強大全面的rad工具;還沒有形成很濃的產業氣候,等等。但是,個人覺得它的好處絕對大於它的缺點,而且很有發展前途。
相比MFC,wxWidgets有著跨平台和開源免費的優勢;相比Qt,wxWidgets的語法是完全C++的,不像Qt的Q_OBJECT宏需要用moc單獨編譯出一個cpp文件再編譯。
使用wxWidgets開發的程序有很多,比較著名的有跨平台3D遊戲0.A.D, 集成編程工具Code::Blocks和CodeLite,文件傳輸工具filezilla
類似於Qt的QtDesigner界面編譯器,wxWidgets也有相應的界面開發工具,如wxSmith和wxFormBuilder,有著非常友好人機交互界面,實現界面可視化開發。

程序示例


下面的例子來源於wxWidgets的官方文檔,實現最簡單的Hello World程序。
wxWidgets
wxWidgets
wxWidgets
wxWidgets
// wxWidgets "Hello world" Program
// For compilers that support precompilation, includes "wx/wx.h".
#ifndef WX_PRECOMP
#include
#endif
class MyApp: public wxApp //這個類用來實現全局消息循環
{public:
virtual bool OnInit(); //在進入消息循環之前調用此函數實現對主窗口類的初始化};
class MyFrame: public wxFrame //主窗口類
{public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();};
enum
{ID_Hello = 1};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Hello, MyFrame::OnHello)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) );
frame->Show( true );
return true;}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{wxMenu *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
wxMenu *menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, "&File" );
menuBar->Append( menuHelp, "&Help" );
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText( "Welcome to wxWidgets!" );}
void MyFrame::OnExit(wxCommandEvent& event)
{Close( true );}
void MyFrame::OnAbout(wxCommandEvent& event)
{wxMessageBox( "This is a wxWidgets' Hello world sample",
"About Hello World", wxOK | wxICON_INFORMATION );}
void MyFrame::OnHello(wxCommandEvent& event)
{wxLogMessage("Hello world from wxWidgets!");}