wx網羅系列之入門: 使用wxWidgets編程——第一步

這是我非常喜歡的一個入門教程。我喜歡從這裏出發。排版整理完畢。

 

 

譯者注:出於個人對wxWindgets的愛好,翻譯了此文,總共計8章。在翻譯過程中,力求忠實於原文的表達方法。說真的中西方的表達方式真的有很大不同,單獨看一個句子是沒錯誤,可放聯繫上下文,就根本不是那麼回事,所以想在兩者之間找到一個平衡點,還真是件難事。不管各位怎麼看,我還是會按自己的想法翻譯下去,希望大家還能夠看懂。


介紹

我們現在看到的是另外一種更爲友好的建立winodws程序的方式,使用的是一套稱着wxWidgets的類庫。 嚴格地說wxWidgets不僅僅是一個庫集,它還是一個應用程序框架,這也就意味着它提供有一個的體系結構,使之可以使用這些類來開發完整的應用程序。 使用wxWidgets的好處並沒有就此停住,它也是一個跨平臺的庫。 引用wxWidgets作者的話:

wxWidgets是什麼?
wxWidgets提供了簡單易用的API,讓你在多平臺上編寫GUI應用程序。 使用相應的針對你的平臺(Windows/Unix/Mac)的庫和編譯器(幾乎所有流行的C++編譯器)進行連接(link),你的應用程序會採用與那個平臺相對應的外觀。 在強大的GUI功能方面,wxWidgets提供有: 在線幫助、網絡編程、流、剪貼板拖拉、多線程、各種流行格式圖像的裝載和保存、數據庫支持、HTML瀏覽和打印等許許多多的內容。

wxWidgets擁有很高的品質,實際上,有人可能會使用“商業品質”這個詞彙來形容wxWidgets——意思是說它真的很好,值得付賬。 這點千真萬確,只是如果對於wxWidgets有批評的話,那就是,對於初學者,想要掌握它太難了: 剛開始的學習過程是有點複雜。 對於這個批評的樂觀回覆是一旦程序員掌握了wxWidgets的結構體系,例如它的類、函數和技巧,編寫可用的應用程序將是一個非常有益和相對簡單的過程 也可能有經濟上的回報,wxWidgets是一個相當豐富的框架,以至幾乎可以涉足什麼應用程序領域。

在閱讀本文時,你可能已經猜到我是一名狂熱的wxWidgets支持者。 這是真的,我也很樂意通過這些網頁將我對wxWinodws的熱情傳送給你。

我的計劃是解釋wxWidgets的體系結構以及通過一系列的例程,從最基礎的開始介紹wxWidgets裏的類。 在你完成之後,你應該可以很好地掌握wxWidgets了。

在開始之前,請注意以下幾點:

  • 我並不認爲我是個很不錯的程序員,我也不認爲我對wxWidgets有多精通,但我善於文字,我自信能夠將複雜的問題解釋清楚。
  • 你需要了解C和C++,但不定很詳細。 在你學習wxWidgets的時個,你在C和C++方面的能力會大大增強。 如果你已經看了本網站的上大部分的C++資料,並且理解了,那我就認爲你不會有什麼問題。
  • 你需要理解面向對象編程和類。 在本站裏的大部分資料將再一次有助於你。
  • 剛開始是在Windows平臺上完成的。Win95, Win98 和 Win2K 全都用到了。 隨同wxWidgets包一起的MingW提供的是開發環境。

如果你對C++編程還是個初學者,而你又想快速地進入使用wxWidgets開發“真實世界(real-world)”的GUI程序的殿堂,這幾頁將對你有很大的幫助。 跟着來吧!


wxWidgets體系結構和第一個程序

這只是個開始,而且我在一開始我就已經做了簡化。 wxWidgets框架的第一個體系結構就是保持最簡單的觀點。 隨着我們的深入,關於該框架我們會了解更多。

wxWidgets GUI程序的組成:

  • 一個應用程序對象——wxApp類的一個實例
  • 一個框架對象——wxFrame類的一個實例 一個框架(frame)可以有象菜單欄(menubar)、狀態欄(statusbar)、圖標(icon)等等內容。
  • 框架(frame)就是個容器,可以容納許多其它象文本控制器(text control)、按鈕(button)、分割器( splitter)等一樣的對象。

在最簡單的程序裏,我們可能只有一個空的構架(frame),而且這個也是我們看到的第一個基本例子。 讓人迷惘它到底有什麼用是情有可原的。 如果沒有其它的內容,它很更有指導意義,那也是我們首先看它的原因。 你會看到它顯示出了windows應用程序所有的常見行爲。 它有一個系統菜單,可以到處移動,可以改變大小並且可以關閉。


我知道它看起來並不怎麼樣,可它是我們的! 它也顯示給我們這個程序展示的是本地GUI的外觀。 這裏是Windows 98,但是要記住wxWidgets是一個跨平臺的框架而且可以用來爲其它平臺(象Linux,OS2,Mac等等)開發應用程序。

第一個例子的源代碼顯示如下:



 #ifndef BASIC_H
#define BASIC_H
class BasicApplication : public wxApp
{
public:
virtual bool OnInit();
};
 class BasicFrame : public wxFrame
{
public:
BasicFrame( const wxChar *title, int xpos, int ypos,
int width, int height);
~BasicFrame();
};
#endif

這是頭文件。 在這個基本的程序裏我們聲明瞭兩個類:

  • 繼承於wxAppBasicApplication
  • 繼承於wxFrameBasicFrame

我們爲BasicFrame聲明瞭構造函數和析構函數,但對於BasicApplication我們唯一做的就是重載了Oninit()方法。 注意,因爲我們是在重載,所以我們把該方法聲明爲虛擬的(virtual)。

 #include <wx/wx.h>
#include "basic.h"
 IMPLEMENT_APP(BasicApplication)
 bool BasicApplication::OnInit()
{
BasicFrame *frame = new BasicFrame("Basic", 50, 50, 450, 300);
frame->Show(TRUE);
SetTopWindow(frame);
return TRUE;
}
 BasicFrame::BasicFrame (const wxChar *title, int xpos,
int ypos, int width, int height)
: wxFrame ( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height) )
{
}
 BasicFrame::~BasicFrame() { } 

這是實現,類的定義聲明在basic.h裏。

要注意的第一件事是宏(macro)

IMPLEMENT_APP(BasicApplication)

依據我們的觀點,它構造了BasicApplication對象而且爲我們的應用程序提供了main入口。 它虛擬地代替了我們前面的課程裏在函數 int WINAPI WinMain( ... )中所做的所有的工作。

方法OnInit()創建了BasicFrame的一個實例,使用了默認的x和y, width(寬度)和height(高度),以及title(標題)。 它然後調用方法Show()來顯示框架(frame)。 如果你查看wxFrame類,你會找不到方法Show()。wxFrame繼承於wxWindow,而Show()是wxWindow的成員函數。 作爲初學者,你需要記住這一點——因爲許多類的都繼承於其它類,所以不要忽略可能是父類提供的方法。

OnInit()也調用了wxApp的一個成員SetTopWindow()

構造函數和析構函數沒有增加任何新的動作給我們的BasicFrame類。

 #include "wx/msw/wx.rc" 
最後一個相關的文件是資源文件。 在這個簡單的例子裏,我們沒有增加任何自己的資源文件,不過你或許經常使用資源文件,而且裏邊至少包含這樣一行:

#include "wx/msw/wx.rc"

在後面的例子裏,我們會添加自己的資源。


所有剩下的工作就是建立和運行程序了。



使用MingW來建立wxWidgets程序

wxWidgets發行包裏有許多的實例,而且所有的實例都有針對不同平臺的make文件。 儘管這是個產生程序的很好的方法(因爲用戶不必在意指定所有的確定生成何種目標程序的細節),但我必須承認我發現它讓人有點迷惑。 正如我隨意感覺到的一樣,也有一個不利的地方,那就建立(build)的過程必須要指定包含文件和庫在什麼地方。 我發現把wxWidgets包含文件放在標準的包含目錄,而把wxWidgets庫放在標準庫目錄裏會更有幫助。 在建立和安裝好庫後,我會把它和wx包含目錄移動到標準位置裏。 在Windows系統裏該位置在MingW目錄裏(譯者注:我的MingW安裝在E:/mingw/bin;而wxWidgets安裝目錄是F:/wxWidgets-2.5.2),而在Linux系統裏它可以是在/usr或者/usr/local樹裏(usr/lib, /usr/include 或 /usr/local/lib, /usr/local/include)。

重新調整庫和包含文件位置的主要好處是它可以排除可能給初學者帶來的困惑。 這個完成後,我們現在使用下面的make文件來建立(build)程序(譯者注:爲了適應最新版本,所以做了較大的改動,以後的實例都會在些make文件的基礎上進行修改使用):

 PROGRAM = basic
OBJECTS = ${PROGRAM}.o ${PROGRAM}_resources.o
RC = windres.exe
CC = g++
INCLUDES = -IF:/wxWidgets-2.5.2/include -IF:/wxWidgets-2.5.2/lib/gcc_lib/mswd -I.
LIBS = -lwxmsw25d_core -lwxbase25d -lwxtiffd -lwxjpegd -lwxpngd / -lwxzlibd -lwsock32
-lwxregexd -lwxexpatd -lkernel32 -luser32 / -lgdi32 -lcomdlg32 -lwinspool -lwinmm
-lshell32 -lcomctl32 -lole32 / -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lodbc32
RESSW = ${INCLUDES} --use-temp-file --define __WXMSW__
CCSW1 = -LF:/wxWidgets-2.5.2/lib/gcc_lib -g -O0 -DHAVE_W32API_H -D__WXMSW__ / -D__WXDEBUG__ -Wall
CCSW2 = -LF:/wxWidgets-2.5.2/lib/gcc_lib -Wl,--subsystem,windows -mwindows
.SUFFIXES: .o .cpp
all: ${OBJECTS} $(CC) -o $(PROGRAM) ${OBJECTS} ${CCSW2} ${LIBS}
.cpp .o: $(CC) ${CCSW1} ${INCLUDES} -c -o $@ ___FCKpd___3lt;
${PROGRAM}_resources.o: $(RC) ${RESSW} ${PROGRAM}_resources.rc $@
.PHONY : clean
clean: echo cleaning up
rm $(OBJECTS)
rm *.$
rm ${PROGRAM}.exe
(皿按:由於對Makefile結構還不夠熟悉,排版整理中可能帶入錯誤,)


建立(build)程序:
  1. 在一個單一目錄裏創建資源文件
    • basic.h
    • basic.cpp
    • basic_resources.rc
    • Makefile
  2. 在存放那些文件的目錄裏運行make
    • make
  3. 運行程序
    • basic

我們使用了的wxWidgets類

我們只使用了兩個類:

  • wxApp
  • wxFrame

我們從那裏繼承了自己的類了BasicApplication和BasicFrame。 我會詳細說明兩個類,不過你也可以閱讀wxWidgets文檔裏的更多完整的描述。

wxApp

wxApp類包含了大約30多個可以訪問的成員,不過在這裏我們並不需要查看wxApp裏的任何細節。 後面在我們使用wxWidgets事件系統完成任務時,我們會再討論wxApp。

wxFrame

因爲wxFrame類所做工作的“可見性(visible)”更強,所以我們要花費一點點的時間來看看它的一些屬性。

wxFrame構造函數
 wxFrame ( wxWindow* parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = "frame" )

我們的BasicFrame構造函數只提供了四個常見的參數: 標題(title),座標x和y,以及寬度(width)和高度(height)。

wxFrame構造函數還有其它的參數: wxWidgets指針、樣式(style)、名字(name)和wxWidgetsID,最後那個是個整數,而且如果它爲-1的話,就使用默認值。 提供自己的ID有時會很有用。 指針會指向父窗口,如果有的話。 在這裏,指針爲空(NULL),即沒有父窗口。 名字參數可以象參數ID一樣,由程序員來提供,在引用一個框架(frame)也許會有用處。

框架(frame)樣式可以各式各樣:

窗口樣式

  • wxDEFAULT_FRAME_STYLE 可以被定義爲 wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BOX | wxSYSTEM_MENU | wxCAPTION。
  • wxICONIZE 圖標化(最小化)顯示框架(frame)。 僅限於Windows。
  • wxCAPTION 在框架(frame)上顯示標題。
  • wxMINIMIZE 等效於 wxICONIZE。 僅限於Windows。
  • wxMINIMIZE_BOX 在框架上最小化顯示盒框(box)。
  • wxMAXIMIZE 最大化顯示框架(frame)。 僅限於Windows。
  • wxMAXIMIZE_BOX 在框架上最大化顯示盒框(box)。
  • wxSTAY_ON_TOP 保持在其它窗口的上方。 僅限於Windows。
  • wxSYSTEM_MENU 顯示系統菜單。
  • wxSIMPLE_BORDER 無邊界顯示或無任何修飾。 僅限於GTK和Windows。
  • wxRESIZE_BORDER 在窗口四周顯示可變大小邊界(僅限於Unix)。
  • wxFRAME_FLOAT_ON_PARENT 讓框架(frame)位於父窗口z軸方向的上方,而不是顯示在任務欄上。 如果沒有這個樣式,建立爲最上層窗口的框架可能被父窗口擋住,而且框架的標題也會顯示在任務欄。 限於Windows和GTK。
  • wxFRAME_TOOL_WINDOW 建立一個帶有小標題欄的框架(frame);框架(frame)標題不會出現在任務欄。 僅限於Windows。

一個框架(frame)樣式是一個或多個樣式的“或(OR)”運算。 在沒有定義樣式時(如我們的BasicFrame),就使用默認的。例如BasicFrame會有一個最小化的盒框,一個最大化的盒框,一個系統菜單,一個標題而且可以改變大小。

要做的修改……
 BasicFrame::BasicFrame (const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame ( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height), wxSIMPLE_BORDER ) ...

這樣你可以看到不同樣式的不同效果;象這裏顯示的那們,修改BasicFrame的構造函數,這樣一個樣式就會做爲參數傳遞給wxFrame構造函數。



在wxFrame的成員中,大約有二三十個是方法:

  • CreateStatusBar
  • CreateToolBar
  • GetTitle
  • SetIcon
  • SetMenuBar
  • SetStatusBar
  • SetStatusText
  • SetToolBar
  • SetTitle

在後面的部分,你會使用它們中的大部分,不過現在有個使用SetTitle和GetTitle成員函數的練習。

框架(frame)標題和框架(frame)名字
 BasicFrame::BasicFrame (const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height), wxDEFAULT_FRAME_STYLE, "Fred" )
{
}
爲了傳遞名字給wxFrame的構造函數,該構造函數已經作了修改。 現在新增這樣一行:
 frame->SetTitle(frame->GetTitle() + " " + frame->GetName()); 

到函數BasicApplication::OnInit(),並且在frame->Show(true)一行的前面。

建立運行程序,你就會看到效果了。 方法GetName()是從哪裏來的呢?




總結

在這個部分,你已經對wxWidgets有了大致的瞭解。 你見到了基本的wxWidgets框架,而且對它的體系結構有了一定的概念。 不要忘了查看wxWidgets文檔的類參考手冊。 剛開始你可能會發覺它讓人有點迷惑,不過在練習之後,效果就會不同了。 同時我也建議,在機會合適的時候(應該經常有的),你應該看看wxWidgets的源代碼。 在裏邊,你會發現許多有用的註釋,同時也會開始領悟這個優秀軟件包裏所蘊藏的精髓 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章