Qt圖形編程基礎(chǔ)之:Qt/Embedded開(kāi)發(fā)入門
掃描二維碼
隨時(shí)隨地手機(jī)看文章
Qt/Embedded以原始Qt為基礎(chǔ),并做了許多出色的調(diào)整以適用于嵌入式環(huán)境。Qt/Embedded通過(guò)QtAPI與LinuxI/O設(shè)施直接交互,成為嵌入式Linux端口。同Qt/X11相比,Qt/Embedded很省內(nèi)存,因?yàn)樗恍枰粋€(gè)X服務(wù)器或是Xlib庫(kù),它在底層拋棄了Xlib,采用framebuffer(幀緩沖)作為底層圖形接口。同時(shí),將外部輸入設(shè)備抽象為keyboard和mouse輸入事件。Qt/Embedde的應(yīng)用程序可以直接寫內(nèi)核緩沖幀,這避免開(kāi)發(fā)者使用繁瑣的Xlib/Server系統(tǒng)。圖12.1所示比較了Qt/Embedded與Qt/X11的架構(gòu)區(qū)別。
使用單一的API進(jìn)行跨平臺(tái)的編程可以有很多好處。提供嵌入式設(shè)備和桌面計(jì)算機(jī)環(huán)境下應(yīng)用的公司可以培訓(xùn)開(kāi)發(fā)人員使用同一套工具開(kāi)發(fā)包,這有利于開(kāi)發(fā)人員之間共享開(kāi)發(fā)經(jīng)驗(yàn)與知識(shí),也使得管理人員在分配開(kāi)發(fā)人員到項(xiàng)目中的時(shí)候增加靈活性。更進(jìn)一步來(lái)說(shuō),針對(duì)某個(gè)平臺(tái)而開(kāi)發(fā)的應(yīng)用和組件也可以銷售到Qt支持的其他平臺(tái)上,從而以低廉的成本擴(kuò)大產(chǎn)品的市場(chǎng)。
(1)窗口系統(tǒng)。
一個(gè)Qt/Embedded窗口系統(tǒng)包含了一個(gè)或多個(gè)進(jìn)程,其中的一個(gè)進(jìn)程可作為服務(wù)器。該服務(wù)進(jìn)程會(huì)分配客戶顯示區(qū)域,以及產(chǎn)生鼠標(biāo)和鍵盤事件。該服務(wù)進(jìn)程還能夠提供輸入方法和一個(gè)用戶接口給運(yùn)行起來(lái)的客戶應(yīng)用程序。該服務(wù)進(jìn)程其實(shí)就是一個(gè)有某些額外權(quán)限的客戶進(jìn)程。任何程序都可以在命令行上加上“-qws”的選項(xiàng)來(lái)把它作為一個(gè)服務(wù)器運(yùn)行。
客戶與服務(wù)器之間的通信使用共享內(nèi)存的方法實(shí)現(xiàn),通信量應(yīng)該保持最小,例如客戶進(jìn)程直接訪問(wèn)幀緩沖來(lái)完成全部的繪制操作,而不會(huì)通過(guò)服務(wù)器,客戶程序需要負(fù)責(zé)繪制它們自己的標(biāo)題欄和其他式樣。這就是Qt/Embedded庫(kù)內(nèi)部層次分明的處理過(guò)程。客戶可以使用QCOP通道交換消息。服務(wù)進(jìn)程簡(jiǎn)單的廣播QCOP消息給所有監(jiān)聽(tīng)指定通道的應(yīng)用進(jìn)程,接著應(yīng)用進(jìn)程可以把一個(gè)插槽連接到一個(gè)負(fù)責(zé)接收的信號(hào)上,從而對(duì)消息做出響應(yīng)。消息的傳遞通常伴隨著二進(jìn)制數(shù)據(jù)的傳輸,這是通過(guò)一個(gè)QDataStream類的序列化過(guò)程來(lái)實(shí)現(xiàn)的,有關(guān)這個(gè)類的描述,請(qǐng)讀者參考相關(guān)資料。
QProcess類提供了另外一種異步的進(jìn)程間通信機(jī)制。它用于啟動(dòng)一個(gè)外部的程序并且通過(guò)寫一個(gè)標(biāo)準(zhǔn)的輸入和讀取外部程序的標(biāo)準(zhǔn)輸出和錯(cuò)誤碼來(lái)和它們通信。
(2)字體
Qt/Embedded支持4種不同的字體格式:TrueType字體(TTF),PostscriptType1字體,位圖發(fā)布字體(BDF)和Qt的預(yù)呈現(xiàn)(Pre-rendered)字體(QPF)。Qt還可以通過(guò)增加Qfont-
Factory的子類來(lái)支持其他字體,也可以支持以插件方式出現(xiàn)的反別名字體。
每個(gè)TTF或者TYPE1類型的字體首次在圖形或者文本方式的環(huán)境下被使用時(shí),這些字體的字形都會(huì)以指定的大小被預(yù)先呈現(xiàn)出來(lái),呈現(xiàn)的結(jié)果會(huì)被緩沖。根據(jù)給定的字體尺寸(例如10或12點(diǎn)陣)預(yù)先呈現(xiàn)TTF或者TYPE1類型的字體文件并把結(jié)果以QPF的格式保存起來(lái),這樣可以節(jié)省內(nèi)存和CPU的處理時(shí)間。QPF文件包含了一些必要的字體,這些字體可以通過(guò)makeqpf工具取得,或者通過(guò)運(yùn)行程序時(shí)加上“-savefonts”選項(xiàng)獲取。如果應(yīng)用程序中使用到的字體都是QPF格式,那么Qt/Embedded將被重新配置,并排除對(duì)TTF和TYPE1類型的字體的編譯,這樣就可以減少Q(mào)t/Embedded的庫(kù)的大小和存儲(chǔ)字體的空間。例如一個(gè)10點(diǎn)陣大小的包含所有ASCII字符的QPF字體文件的大小為1300字節(jié),這個(gè)文件可以直接從物理存儲(chǔ)格式映射成為內(nèi)存存儲(chǔ)格式。
Qt/Embedded的字體通常包括Unicode字體的一部分子集,ASCII和Latin-1。一個(gè)完整的16點(diǎn)陣的Unicode字體的存儲(chǔ)空間通常超過(guò)1MB,我們應(yīng)盡可能存儲(chǔ)一個(gè)字體的子集,而不是存儲(chǔ)所有的字,例如在一個(gè)應(yīng)用中,僅僅需要以Cappuccino字體、粗體的方式顯示產(chǎn)品的名稱,但是卻有一個(gè)包含了全部字形的字體文件。
(3)輸入設(shè)備及輸入法。
Qt/Embedded3.0支持幾種鼠標(biāo)協(xié)議:BusMouse、IntelliMouse,Microsoft和MouseMan.Qt/
Embedded還支持NECVr41XX和iPAQ的觸摸屏。通過(guò)從QWSMouseHandler或者Qcalibra-
tedMouseHandler派生子類,開(kāi)發(fā)人員可以讓Qt/Embedded支持更多的客戶指示設(shè)備。
Qt/Embedded支持標(biāo)準(zhǔn)的101鍵盤和Vr41XX按鍵,通過(guò)子類化QWSKeyboardHandler可以讓Qt/Embedded支持更多的客戶鍵盤和其他的非指示設(shè)備。
對(duì)于非拉丁語(yǔ)系字符(例如阿拉伯、中文、希伯來(lái)和日語(yǔ))的輸入法,需要把它寫成過(guò)濾器的方式,并改變鍵盤的輸入。輸入法的作者應(yīng)該對(duì)全部的QtAPI的使用有完整的認(rèn)識(shí)。在一個(gè)無(wú)鍵盤的設(shè)備上,輸入法成了惟一的輸入字符的手段。Qtopia提供了4種輸入方法:筆跡識(shí)別器、圖形化的標(biāo)準(zhǔn)鍵盤、Unicode鍵盤和基于字典方式提取的鍵盤。
(4)屏幕加速
通過(guò)子類化QScreen和QgfxRaster可以實(shí)現(xiàn)硬件加速,從而為屏幕操作帶來(lái)好處。Troll-
tech提供了Mach64和Voodoo3視頻卡的硬件加速的驅(qū)動(dòng)例子,同時(shí)可以按照協(xié)議編寫其他的驅(qū)動(dòng)程序。
Qt/Embedded的開(kāi)發(fā)環(huán)境可以取代那些我們熟知的UNIX和Windows開(kāi)發(fā)工具。它提供了幾個(gè)跨平臺(tái)的工具使得開(kāi)發(fā)變得迅速和方便,尤其是它的圖形設(shè)計(jì)器。UNIX下的開(kāi)發(fā)者可以在PC機(jī)或者工作站使用虛擬緩沖幀,從而可以模仿一個(gè)和嵌入式設(shè)備的顯示終端大小,像素相同的顯示環(huán)境。
嵌入式設(shè)備的應(yīng)用可以在安裝了一個(gè)跨平臺(tái)開(kāi)發(fā)工具鏈的不同的平臺(tái)上編譯。最通常的做法是在一個(gè)UNIX系統(tǒng)上安裝跨平臺(tái)的帶有l(wèi)ibc庫(kù)的GNUC++編譯器和二進(jìn)制工具。在開(kāi)發(fā)的許多階段,一個(gè)可替代的做法是使用Qt的桌面版本,例如通過(guò)Qt/X11或是Qt/Windows來(lái)進(jìn)行開(kāi)發(fā)。這樣開(kāi)發(fā)人員就可以使用他們熟悉的開(kāi)發(fā)環(huán)境,例如微軟公司的VisualC++或者BorlandC++。在UNIX操作系統(tǒng)下,許多環(huán)境也是可用的,例如Kdevelop,它也支持交互式開(kāi)發(fā)。
如果Qt/Embedded的應(yīng)用是在UNIX平臺(tái)下開(kāi)發(fā)的話,那么它就可以在開(kāi)發(fā)的機(jī)器上以一個(gè)獨(dú)立的控制臺(tái)或者虛擬緩沖幀的方式來(lái)運(yùn)行,對(duì)于后者來(lái)說(shuō),其實(shí)是有一個(gè)X11的應(yīng)用程序虛擬了一個(gè)緩沖幀。通過(guò)指定顯示設(shè)備的寬度、高度和顏色深度,虛擬出來(lái)的緩沖幀將和物理的顯示設(shè)備在每個(gè)像素上保持一致。這樣每次調(diào)試應(yīng)用時(shí)開(kāi)發(fā)人員就不用總是刷新嵌入式設(shè)備的Flash存儲(chǔ)空間,從而加速了應(yīng)用的編譯、鏈接和運(yùn)行周期。運(yùn)行Qt的虛擬緩沖幀工具的方法是在Linux的圖形模式下運(yùn)行以下命令:
qvfb(回車)
當(dāng)Qt嵌入式的應(yīng)用程序要把顯示結(jié)果輸出到虛擬緩沖幀時(shí),我們?cè)诿钚羞\(yùn)行這個(gè)程序,并在程序名后加上-qws的選項(xiàng)。例如:$>hello–qws。
3.Qt的支撐工具Qt包含了許多支持嵌入式系統(tǒng)開(kāi)發(fā)的工具,有兩個(gè)最實(shí)用的工具是qmake和Qtdesigner(圖形設(shè)計(jì)器)。
n qmake是一個(gè)為編譯Qt/Embedded庫(kù)和應(yīng)用而提供的Makefile生成器。它能夠根據(jù)一個(gè)工程文件(.pro)產(chǎn)生不同平臺(tái)下的Makefile文件。qmake支持跨平臺(tái)開(kāi)發(fā)和影子生成,影子生成是指當(dāng)工程的源代碼共享給網(wǎng)絡(luò)上的多臺(tái)機(jī)器時(shí),每臺(tái)機(jī)器編譯鏈接這個(gè)工程的代碼將在不同的子路徑下完成,這樣就不會(huì)覆蓋別人的編譯鏈接生成的文件。qmake還易于在不同的配置之間切換。
n Qt圖形設(shè)計(jì)器可以使開(kāi)發(fā)者可視化地設(shè)計(jì)對(duì)話框而不需編寫代碼。使用Qt圖形設(shè)計(jì)器的布局管理可以生成能平滑改變尺寸的對(duì)話框。
qmake和Qt圖形設(shè)計(jì)器是完全集成在一起的。
12.2.2Qt/Embedded信號(hào)和插槽機(jī)制1.機(jī)制概述信號(hào)和插槽機(jī)制是Qt的核心機(jī)制,要精通Qt編程就必須對(duì)信號(hào)和插槽有所了解。信號(hào)和插槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是Qt的核心特性,也是Qt區(qū)別于其他工具包的重要地方。信號(hào)和插槽是Qt自行定義的一種通信機(jī)制,它獨(dú)立于標(biāo)準(zhǔn)的C/C++語(yǔ)言,因此要正確地處理信號(hào)和插槽,必須借助一個(gè)稱為moc(MetaObjectCompiler)的Qt工具,該工具是一個(gè)C++預(yù)處理程序,它為高層次的事件處理自動(dòng)生成所需要的附加代碼。
所謂圖形用戶接口的應(yīng)用就是要對(duì)用戶的動(dòng)作做出響應(yīng)。例如,當(dāng)用戶單擊了一個(gè)菜單項(xiàng)或是工具欄的按鈕時(shí),應(yīng)用程序會(huì)執(zhí)行某些代碼。大部分情況下,是希望不同類型的對(duì)象之間能夠進(jìn)行通信。程序員必須把事件和相關(guān)代碼聯(lián)系起來(lái),這樣才能對(duì)事件做出響應(yīng)。以前的工具開(kāi)發(fā)包使用的事件響應(yīng)機(jī)制是易崩潰的,不夠健壯的,同時(shí)也不是面向?qū)ο蟮摹?/p>
以前,當(dāng)使用回調(diào)函數(shù)機(jī)制把某段響應(yīng)代碼和一個(gè)按鈕的動(dòng)作相關(guān)聯(lián)時(shí),通常把那段響應(yīng)代碼寫成一個(gè)函數(shù),然后把這個(gè)函數(shù)的地址指針傳給按鈕,當(dāng)那個(gè)按鈕被單擊時(shí),這個(gè)函數(shù)就會(huì)被執(zhí)行。對(duì)于這種方式,以前的開(kāi)發(fā)包不能夠確保回調(diào)函數(shù)被執(zhí)行時(shí)所傳遞進(jìn)來(lái)的函數(shù)參數(shù)就是正確的類型,因此容易造成進(jìn)程崩潰。另外一個(gè)問(wèn)題是,回調(diào)這種方式緊緊地綁定了圖形用戶接口的功能元素,因而很難進(jìn)行獨(dú)立的開(kāi)發(fā)。
信號(hào)與插槽機(jī)制是不同的。它是一種強(qiáng)有力的對(duì)象間通信機(jī)制,完全可以取代原始的回調(diào)和消息映射機(jī)制。在Qt中信號(hào)和插槽取代了上述這些凌亂的函數(shù)指針,使得用戶編寫這些通信程序更為簡(jiǎn)潔明了。信號(hào)和插槽能攜帶任意數(shù)量和任意類型的參數(shù),它們是類型完全安全的,因此不會(huì)像回調(diào)函數(shù)那樣產(chǎn)生coredumps。
圖12.2對(duì)象間信號(hào)與插槽的關(guān)系
所有從QObject或其子類(例如Qwidget)派生的類都能夠包含信號(hào)和插槽。當(dāng)對(duì)象改變狀態(tài)時(shí),信號(hào)就由該對(duì)象發(fā)射(emit)出去了,這就是對(duì)象所要做的全部工作,它不知道另一端是誰(shuí)在接收這個(gè)信號(hào)。這就是真正的信息封裝,它確保對(duì)象被當(dāng)作一個(gè)真正的軟件組件來(lái)使用。插槽用于接收信號(hào),但它們是普通的對(duì)象成員函數(shù)。一個(gè)插槽并不知道是否有任何信號(hào)與自己相連接。而且,對(duì)象并不了解具體的通信機(jī)制。
用戶可以將很多信號(hào)與單個(gè)插槽進(jìn)行連接,也可以將單個(gè)信號(hào)與很多插槽進(jìn)行連接,甚至將一個(gè)信號(hào)與另外一個(gè)信號(hào)相連接也是可能的,這時(shí)無(wú)論第一個(gè)信號(hào)什么時(shí)候發(fā)射,系統(tǒng)都將立刻發(fā)射第二個(gè)信號(hào)。總之,信號(hào)與插槽構(gòu)造了一個(gè)強(qiáng)大的部件編程機(jī)制。
2.信號(hào)與插槽實(shí)現(xiàn)實(shí)例(1)信號(hào)。
當(dāng)某個(gè)信號(hào)對(duì)其客戶或所有者內(nèi)部狀態(tài)發(fā)生改變時(shí),信號(hào)就被一個(gè)對(duì)象發(fā)射。只有定義了這個(gè)信號(hào)的類及其派生類才能夠發(fā)射這個(gè)信號(hào)。當(dāng)一個(gè)信號(hào)被發(fā)射時(shí),與其相關(guān)聯(lián)的插槽將被立刻執(zhí)行,就像一個(gè)正常的函數(shù)調(diào)用一樣。信號(hào)-插槽機(jī)制完全獨(dú)立于任何GUI事件循環(huán)。只有當(dāng)所有的槽返回以后發(fā)射函數(shù)(emit)才返回。如果存在多個(gè)槽與某個(gè)信號(hào)相關(guān)聯(lián),那么,當(dāng)這個(gè)信號(hào)被發(fā)射時(shí),這些槽將會(huì)一個(gè)接一個(gè)地執(zhí)行,但是它們執(zhí)行的順序?qū)?huì)是隨機(jī)的、不確定的,用戶不能人為地指定哪個(gè)先執(zhí)行、哪個(gè)后執(zhí)行。
Qt的signals關(guān)鍵字指出進(jìn)入了信號(hào)聲明區(qū),隨后即可聲明自己的信號(hào)。例如,下面定義了3個(gè)信號(hào):
signals:
voidmySignal();
voidmySignal(intx);
voidmySignalParam(intx,inty);
在上面的定義中,signals是Qt的關(guān)鍵字,而非C/C++的。接下來(lái)的一行voidmySignal()定義了信號(hào)mySignal,這個(gè)信號(hào)沒(méi)有攜帶參數(shù);接下來(lái)的一行voidmySignal(intx)定義了重名信號(hào)mySignal,但是它攜帶一個(gè)整形參數(shù),這有點(diǎn)類似于C++中的虛函數(shù)。從形式上講信號(hào)的聲明與普通的C++函數(shù)是一樣的,但是信號(hào)卻沒(méi)有函數(shù)體定義。另外,信號(hào)的返回類型都是void。信號(hào)由moc自動(dòng)產(chǎn)生,它們不應(yīng)該在.cpp文件中實(shí)現(xiàn)。
(2)插槽。
插槽是普通的C++成員函數(shù),可以被正常調(diào)用,它們惟一的特殊性就是很多信號(hào)可以與其相關(guān)聯(lián)。當(dāng)與其關(guān)聯(lián)的信號(hào)被發(fā)射時(shí),這個(gè)插槽就會(huì)被調(diào)用。插槽可以有參數(shù),但插槽的參數(shù)不能有缺省值。
插槽是普通的成員函數(shù),因此與其他的函數(shù)一樣,它們也有存取權(quán)限。插槽的存取權(quán)限決定了誰(shuí)能夠與其相關(guān)聯(lián)。同普通的C++成員函數(shù)一樣,插槽函數(shù)也分為3種類型,即publicslots、privateslots和protectedslots。
n publicslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著任何對(duì)象都可將信號(hào)與之相連接。這對(duì)于組件編程非常有用,用戶可以創(chuàng)建彼此互不了解的對(duì)象,將它們的信號(hào)與槽進(jìn)行連接以便信息能夠正確地傳遞。
n protectedslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著當(dāng)前類及其子類可以將信號(hào)與之相連接。這適用于那些槽,它們是類實(shí)現(xiàn)的一部分,但是其界面接口卻面向外部。
n privateslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著只有類自己可以將信號(hào)與之相連接。這適用于聯(lián)系非常緊密的類。
插槽也能夠被聲明為虛函數(shù),這也是非常有用的。插槽的聲明也是在頭文件中進(jìn)行的。例如,下面聲明了3個(gè)插槽:
publicslots:
voidmySlot();
voidmySlot(intx);
voidmySignalParam(intx,inty);
(3)信號(hào)與插槽關(guān)聯(lián)。
通過(guò)調(diào)用QObject對(duì)象的connect()函數(shù)可以將某個(gè)對(duì)象的信號(hào)與另外一個(gè)對(duì)象的插槽函數(shù)或信號(hào)相關(guān)聯(lián),當(dāng)發(fā)射者發(fā)射信號(hào)時(shí),接收者的槽函數(shù)或信號(hào)將被調(diào)用。
該函數(shù)的定義如下所示:
boolQObject::connect(constQObject*sender,constchar*signal,constQObject*receiver,constchar*member)[static]
這個(gè)函數(shù)的作用就是將發(fā)射者sender對(duì)象中的信號(hào)signal與接收者receiver中的member插槽函數(shù)聯(lián)系起來(lái)。當(dāng)指定信號(hào)signal時(shí)必須使用Qt的宏SIGNAL(),當(dāng)指定插槽函數(shù)時(shí)必須使用宏SLOT()。如果發(fā)射者與接收者屬于同一個(gè)對(duì)象的話,那么在connect()調(diào)用中接收者參數(shù)可以省略。
n 信號(hào)與插槽相關(guān)聯(lián)。
下例定義了兩個(gè)對(duì)象:標(biāo)簽對(duì)象label和滾動(dòng)條對(duì)象scroll,并將valueChanged()信號(hào)與標(biāo)簽對(duì)象的setNum()插槽函數(shù)相關(guān)聯(lián),另外信號(hào)還攜帶了一個(gè)整型參數(shù),這樣標(biāo)簽總是顯示滾動(dòng)條所處位置的值。
QLabel*label=newQLabel;
QScrollBar*scroll=newQScrollBar;
QObject::connect(scroll,SIGNAL(valueChanged(int)),label,SLOT(setNum(int)));
n 信號(hào)與信號(hào)相關(guān)聯(lián)。
在下面的構(gòu)造函數(shù)中,MyWidget創(chuàng)建了一個(gè)私有的按鈕aButton,按鈕的單擊事件產(chǎn)生的信號(hào)clicked()與另外一個(gè)信號(hào)aSignal()進(jìn)行關(guān)聯(lián)。這樣,當(dāng)信號(hào)clicked()被發(fā)射時(shí),信號(hào)aSignal()也接著被發(fā)射。如下所示:
classMyWidget:publicQWidget
{
public:
MyWidget();
...
signals:
voidaSignal();
...
private:
...
QPushButton*aButton;
};
MyWidget::MyWidget()
{
aButton=newQPushButton(this);
connect(aButton,SIGNAL(clicked()),SIGNAL(aSignal()));
}
(4)解除信號(hào)與插槽關(guān)聯(lián)。
當(dāng)信號(hào)與槽沒(méi)有必要繼續(xù)保持關(guān)聯(lián)時(shí),用戶可以使用disconnect()函數(shù)來(lái)斷開(kāi)連接。其定義如下所示:
boolQObject::disconnect(constQObject*sender,constchar*signal,constObject*receiver,constchar*member)[static]
這個(gè)函數(shù)斷開(kāi)發(fā)射者中的信號(hào)與接收者中的槽函數(shù)之間的關(guān)聯(lián)。
有3種情況必須使用disconnect()函數(shù)。
n 斷開(kāi)與某個(gè)對(duì)象相關(guān)聯(lián)的任何對(duì)象。
當(dāng)用戶在某個(gè)對(duì)象中定義了一個(gè)或者多個(gè)信號(hào),這些信號(hào)與另外若干個(gè)對(duì)象中的槽相關(guān)聯(lián),如果想要切斷這些關(guān)聯(lián)的話,就可以利用這個(gè)方法,非常簡(jiǎn)潔。如下所示:
disconnect(myObject,0,0,0)
或者
myObject->disconnect()
n 斷開(kāi)與某個(gè)特定信號(hào)的任何關(guān)聯(lián)。
這種情況是非常常見(jiàn)的,其典型用法如下所示:
disconnect(myObject,SIGNAL(mySignal()),0,0)
或者
myObject->disconnect(SIGNAL(mySignal()))
n 斷開(kāi)兩個(gè)對(duì)象之間的關(guān)聯(lián)。
這也是非常常用的情況,如下所示:
disconnect(myObject,0,myReceiver,0)
或者
myObject->disconnect(myReceiver)
注意
在disconnect()函數(shù)中0可以用作一個(gè)通配符,分別表示任何信號(hào)、任何接收對(duì)象、接收對(duì)象中的任何槽函數(shù)。但是發(fā)射者sender不能為0,其他3個(gè)參數(shù)的值可以等于0。
12.2.3搭建Qt/Embedded開(kāi)發(fā)環(huán)境一般來(lái)說(shuō),用Qt/Embedded開(kāi)發(fā)的應(yīng)用程序最終會(huì)發(fā)布到安裝有嵌入式Linux操作系統(tǒng)的小型設(shè)備上,所以使用裝有Linux操作系統(tǒng)的PC機(jī)或者工作站來(lái)完成Qt/Embedded開(kāi)發(fā)當(dāng)然是最理想的環(huán)境,此外Qt/Embedded也可以安裝在UNIX或Windows系統(tǒng)上。這里就以在Linux操作系統(tǒng)中安裝為例進(jìn)行介紹。
這里需要有3個(gè)軟件安裝包:tmake工具安裝包、Qt/Embedded安裝包和Qt的X11版的安裝包。
n tmake1.11或更高版本:生成Qt/Embedded應(yīng)用工程的Makefile文件。
n Qt/Embedded:Qt/Embedded安裝包。
n Qt2.3.2forX11:Qt的X11版的安裝包,產(chǎn)生X11開(kāi)發(fā)環(huán)境所需要的兩個(gè)工具。
注意
這些軟件安裝包都有許多不同的版本,由于版本的不同會(huì)導(dǎo)致這些軟件在使用時(shí)可能引起的沖突,為此必須依照一定的安裝原則,Qt/Embedded安裝包的版本必須比QtforX11的安裝包的版本新,這是因?yàn)镼tforX11的安裝包中的兩個(gè)工具uic和designer產(chǎn)生的源文件會(huì)和Qt/Embedded的庫(kù)一起被編譯鏈接,因此要本著“向前兼容”的原則,QtforX11的版本應(yīng)比Qt/Embedded的版本舊。
1.安裝tmake用戶使用普通的解壓縮即可,注意要將路徑添加到全局變量中去,如下所示:
tarzxvftmake-1.11.tar.gz
exportTMAKEDIR=$PWD/tmake-1.11
exportTMAKEPATH=$TMAKEDIR/lib/qws/linux-x86-g++
exportPATH=$TMAKEDIR/bin:$PATH
2.安裝Qt/Embedded2.3.7這里使用常見(jiàn)的解壓命令及安裝命令即可,要注意這里的路徑與不同的系統(tǒng)有關(guān),讀者要根據(jù)實(shí)際情況進(jìn)行修改。另外,這里的configure命令帶有參數(shù)“-qconfig–qvfb–depths4816,32”分別為指定Qt嵌入式開(kāi)發(fā)包生成虛擬緩沖幀工具qvfb,并支持4、8、16、32位的顯示顏色深度。另外讀者也可以在configure的參數(shù)中添加“-system”、“-jpeg”或“gif”命令,使Qt/Embedded平臺(tái)能支持jpeg、gif格式的圖形。
Qt/Embedded開(kāi)發(fā)包有5種編譯范圍的選項(xiàng),使用這些選項(xiàng)可控制Qt生成的庫(kù)文件的大小。如命令makesub-src指定按精簡(jiǎn)方式編譯開(kāi)發(fā)包,也就是說(shuō)有些Qt類未被編譯。其他編譯選項(xiàng)的具體用法可通過(guò)“./configure–help”命令查看。精簡(jiǎn)方式的安裝步驟如下所示:
tarzxvfqt-embedded-2.3.7.tar.gz
cdqt-2.3.7
exportQTDIR=$PWD
exportQTEDIR=$QTDIR
exportPATH=$QTDIR/bin:$PATH
exportLD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
./configure-qconfiglocal-qvfb-depths4,8,16,32
makesub-src
3.安裝Qt/X112.3.2與上一步類似,用戶也可以在configure后添加一定的參數(shù),如“-no-opengl”或“-no-xfs”,可以鍵入命令“./configure–help”來(lái)獲得一些幫助信息。
tarxfzqt-x11-2.3.2.tar.gz
cdqt-2.3.2
exportQTDIR=$PWD
exportPATH=$QTDIR/bin:$PATH
exportLD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
./configure-no-opengl
make
make-Ctools/qvfb
mvtools/qvfb/qvfbbin
cpbin/uic$QTEDIR/bin
12.2.4Qt/Embedded窗口部件Qt提供了一整套的窗口部件。它們組合起來(lái)可用于創(chuàng)建用戶界面的可視元素。按鈕、菜單、滾動(dòng)條、消息框和應(yīng)用程序窗口都是窗口部件的實(shí)例。因?yàn)樗械拇翱诓考仁强丶质侨萜鳎虼薗t的窗口部件不能任意地分為控件和容器。通過(guò)子類化已存在的Qt部件或少數(shù)時(shí)候必要的全新創(chuàng)建,自定義的窗口部件能很容易地創(chuàng)建出來(lái)。
窗口部件是QWidget或其子類的實(shí)例,用戶自定義的窗口通過(guò)子類化得到,如圖12.3所示。
圖12.3源自QWidget的類層次結(jié)構(gòu)
一個(gè)窗口部件可包含任意數(shù)量的子部件。子部件在父部件的區(qū)域內(nèi)顯示。沒(méi)有父部件的部件是頂級(jí)部件(比如一個(gè)窗口),通常在桌面的任務(wù)欄上有它們的入口。Qt不在窗口部件上施加任何限制。任何部件都可以是頂級(jí)部件,任何部件都可以是其他部件的子部件。通過(guò)自動(dòng)或手動(dòng)(如果你喜歡)使用布局管理器可以設(shè)定子部件在父部件區(qū)域中的位置。如果父部件被停用、隱藏或刪除,則同樣的動(dòng)作會(huì)應(yīng)用于它的所有子部件。
1.Hello窗口實(shí)例下面是一個(gè)顯示“HelloQt/Embedded!”的程序的完整代碼:
#include<qapplication.h>
#include<qlabel.h>
intmain(intargc,char**argv)
{
QApplicationapp(argc,argv);
QLabel*hello=newQLabel
("<fontcolor=blue>Hello""<i>QtEmbedded!</i></font>",0);
app.setMainWidget(hello);
hello->show();
returnapp.exec();
}
2.常見(jiàn)通用窗口組合Qt中還有一些常見(jiàn)的通用窗口,它們使用了Windows風(fēng)格顯示,圖12.5、12.6、12.7、12.8分別描述了常見(jiàn)的一些通用窗口的組合使用。圖12.4是該Hello窗口的運(yùn)行效果圖:
圖12.4 Hello窗口運(yùn)行效果圖圖12.5 使用QHBox排列一個(gè)標(biāo)簽和一個(gè)按鈕
圖12.6 使用了QButtonGroup的兩個(gè)單選框和兩個(gè)復(fù)選框 圖12.7 QGroupBox組合圖示
圖12.8使用了QGroupBox進(jìn)行排列的日期類QDateTimeEdit、一個(gè)行編輯框類QLine-
Edit、一個(gè)文本編輯類QTextEdit和一個(gè)組合框類QComboBox。
圖12.9是以QGrid排列的一個(gè)QDial、一個(gè)QProgressBar、一個(gè)QSpinBox、一個(gè)QScrollBar、一個(gè)QLCDNumber和一個(gè)QSlider。
圖12.10是以QGrid排列的一個(gè)QIconView、一個(gè)QListView、一個(gè)QListBox和一個(gè)QTable。
圖12.8 QGrid組合圖示1圖12.9 QGrid組合圖示2 圖12.10鐘表部件圖示
3.自定義窗口開(kāi)發(fā)者可以通過(guò)子類化QWidget或它的一個(gè)子類創(chuàng)建他們自己的部件或?qū)υ捒?。為了舉例說(shuō)明子類化,下面提供了數(shù)字鐘部件的完整代碼。
鐘表部件是一個(gè)能顯示當(dāng)前時(shí)間并自動(dòng)更新的LCD。一個(gè)冒號(hào)分隔符隨秒數(shù)的流逝而閃爍,如圖12.10所示。
Clock從QLCDNumber部件繼承了LCD功能。它有一個(gè)典型部件類所擁有的典型構(gòu)造函數(shù),帶有可選的parent和name參數(shù)(如果設(shè)置了name參數(shù),測(cè)試和調(diào)試會(huì)更容易)。系統(tǒng)有規(guī)律地調(diào)用從QObject繼承的timerEvent()函數(shù)。
它在clock.h中定義如下所示:
#include<qlcdnumber.h>
classClock:publicQLCDNumber
{
public:
Clock(QWidget*parent=0,constchar*name=0);
protected:
voidtimerEvent(QTimerEvent*event);
private:
voidshowTime();
boolshowingColon;
};
構(gòu)造函數(shù)showTime()是用當(dāng)前時(shí)間初始化鐘表,并且告訴系統(tǒng)每1000ms調(diào)用一次timerEvent()來(lái)刷新LCD的顯示。在showTime()中,通過(guò)調(diào)用QLCDNumber::display()來(lái)顯示當(dāng)前時(shí)間。每次調(diào)用showTime()來(lái)讓冒號(hào)閃爍時(shí),冒號(hào)就被空白代替。
clock.cpp的源碼如下所示:
#include<qdatetime.h>
#include"clock.h"
Clock::Clock(QWidget*parent,constchar*name)
:QLCDNumber(parent,name),showingColon(true)
{
showTime();
startTimer(1000);
}
voidClock::timerEvent(QTimerEvent*)
{
showTime();
}
voidClock::showTime()
{
QStringtimer=QTime::currentTime().toString().left(5);
if(!showingColon)
{
time[2]='';
}
display(time);
showingColon=!showingColon;
}
文件clock.h和clock.cpp完整地聲明并實(shí)現(xiàn)了Clock部件。
#include<qapplication.h>
#include"clock.h"
intmain(intargc,char**argv)
{
QApplicationapp(argc,argv);
Clock*clock=newClock;
app.setMainWidget(clock);
clock->show();
returnapp.exec();
}
12.2.5Qt/Embedded圖形界面編程Qt提供了所有可能的類和函數(shù)來(lái)創(chuàng)建GUI程序。Qt既可用來(lái)創(chuàng)建“主窗口”式的程序,即一個(gè)有菜單欄,工具欄和狀態(tài)欄作為環(huán)繞的中心區(qū)域;也可以用來(lái)創(chuàng)建“對(duì)話框”式的程序,使用按鈕和必要的選項(xiàng)卡來(lái)呈現(xiàn)選項(xiàng)與信息。Qt支持SDI(單文檔界面)和MDI(多文檔界面)。Qt還支持拖動(dòng)、放下和剪貼板。工具欄可以在工具欄區(qū)域內(nèi)移動(dòng),拖拽到其他區(qū)域或者作為工具托盤浮動(dòng)起來(lái)。這個(gè)功能是內(nèi)建的,不需要額外的代碼,但程序員在需要時(shí)可以約束工具欄的行為。
使用Qt可以大大簡(jiǎn)化編程。例如,如果一個(gè)菜單項(xiàng)、一個(gè)工具欄按鈕和一個(gè)快捷鍵都完成同樣的動(dòng)作,那么這個(gè)動(dòng)作只需要一份代碼。
Qt還提供消息框和一系列標(biāo)準(zhǔn)對(duì)話框,使得程序向用戶提問(wèn)和讓用戶選擇文件、文件夾、字體以及顏色變得更加簡(jiǎn)單。為了呈現(xiàn)一個(gè)消息框或一個(gè)標(biāo)準(zhǔn)對(duì)話框,只需要用一個(gè)使用方便的Qt靜態(tài)函數(shù)的一行的語(yǔ)句。
1.主窗口類QMainWindow類提供了一個(gè)典型應(yīng)用程序的主窗口框架。
一個(gè)主窗口包含了一組標(biāo)準(zhǔn)窗體的集合。主窗口的頂部包含一個(gè)菜單欄,它的下方放置著一個(gè)工具欄,工具欄可以移動(dòng)到其他的停靠區(qū)域。主窗口允許??康奈恢糜许敳?、左邊、右邊和底部。工具欄可以被拖放到一個(gè)??康奈恢?,從而形成一個(gè)浮動(dòng)的工具面板。主窗口的下方,也就是在底部的停靠位置下方有一個(gè)狀態(tài)欄。主窗口的中間區(qū)域可以包含其他的窗體。提示工具和“這是什么”幫助按鈕以旁述的方式闡述了用戶接口的使用方法。
對(duì)于小屏幕的設(shè)備,使用Qt圖形設(shè)計(jì)器定義的標(biāo)準(zhǔn)的QWidget模板比使用主窗口類更好一些。典型的模板包含有菜單欄、工具欄,可能沒(méi)有狀態(tài)欄(在必要的情況下,可以用任務(wù)欄,標(biāo)題欄來(lái)顯示狀態(tài))。
例如,一個(gè)文本編輯器可以把QTextEdit作為中心部件:
QTextEdit*editor=newQTextEdit(mainWindow);
mainWindow->setCentralWidget(editor);
2.菜單類彈出式菜單QPopupMenu類以垂直列表的方式顯示菜單項(xiàng),它可以是單個(gè)的(例如上下文相關(guān)菜單),可以以菜單欄的方式出現(xiàn),或者是別的彈出式菜單的子菜單出現(xiàn)。
每個(gè)菜單項(xiàng)可以有一個(gè)圖標(biāo)、一個(gè)復(fù)選框和一個(gè)加速器(快捷鍵),菜單項(xiàng)通常對(duì)應(yīng)一個(gè)動(dòng)作(例如存盤),分隔器通常顯示成一條豎線,它用于把一組相關(guān)聯(lián)的動(dòng)作菜單分離成組。
下面是一個(gè)建立包含有New、Open和Exit菜單項(xiàng)的文件菜單的例子。
QPopupMenu*fileMenu=newQPopupMenu(this);
fileMenu->insertItem("&New",this,SLOT(newFile()),CTRL+Key_N);
fileMenu->insertItem("&Open...",this,SLOT(open()),CTRL+Key_O);
fileMenu->insertSeparator();
fileMenu->insertItem("&Exit",qApp,SLOT(quit()),CTRL+Key_Q);
當(dāng)一個(gè)菜單項(xiàng)被選中,和它相關(guān)的插槽將被執(zhí)行。加速器(快捷鍵)很少在一個(gè)沒(méi)有鍵盤輸入的設(shè)備上使用,Qt/Embedded的典型配置并未包含對(duì)加速器的支持。上面出現(xiàn)的代碼“&New”意思是在桌面機(jī)器上以“New”的方式顯示出來(lái),但是在嵌入式設(shè)備中,它只會(huì)顯示為“New”。
QMenuBar類實(shí)現(xiàn)了一個(gè)菜單欄,它會(huì)自動(dòng)地設(shè)置幾何尺寸并在它的父窗體的頂部顯示出來(lái),如果父窗體的寬度不夠?qū)捯灾敛荒茱@示一個(gè)完整的菜單欄,那么菜單欄將會(huì)分為多行顯示出來(lái)。Qt內(nèi)置的布局管理能夠自動(dòng)調(diào)整菜單欄。
Qt的菜單系統(tǒng)是非常靈活的,菜單項(xiàng)可以被動(dòng)態(tài)使能、失效、添加或者刪除。通過(guò)子類化QCustomMenuItem,用戶可以建立客戶化外觀和功能的菜單項(xiàng)。
3.工具欄工具欄可以被移動(dòng)到中心區(qū)域的頂部、底部、左邊或右邊。任何工具欄都可以拖拽到工具欄區(qū)域的外邊,作為獨(dú)立的浮動(dòng)工具托盤。
QToolButton類實(shí)現(xiàn)了具有一個(gè)圖標(biāo),一個(gè)3D框架和一個(gè)可選標(biāo)簽的工具欄。切換型工具欄按鈕具有可以打開(kāi)或關(guān)閉某些特征的功能。其他的則會(huì)執(zhí)行一個(gè)命令。可以為活動(dòng)、關(guān)閉、開(kāi)啟等模式,打開(kāi)或關(guān)閉等狀態(tài)提供不同的圖標(biāo)。如果只提供一個(gè)圖標(biāo),Qt能根據(jù)可視化線索自動(dòng)地辨別狀態(tài),例如將禁用的按鈕變灰,工具欄按鈕也能觸發(fā)彈出式菜單。
QToolButton通常在QToolBar內(nèi)并排出現(xiàn)。一個(gè)程序可含有任意數(shù)量的工具欄并且用戶可以自由地移動(dòng)它們。工具欄可以包括幾乎所有部件,例如QComboBox和QSpinBox。
4.旁述現(xiàn)在的應(yīng)用主要使用旁述的方式去解釋用戶接口的用法。Qt提供了兩種旁述的方式,即“提示欄”和“這是什么”幫助按鈕。
n “提示欄”是小的,通常是黃色的矩形,當(dāng)光標(biāo)在窗體的某些位置游動(dòng)時(shí),它就會(huì)自動(dòng)地出現(xiàn)。它主要用于解釋工具欄按鈕,特別是那些缺少文字標(biāo)簽說(shuō)明的工具欄按鈕的用途。下面就是如何設(shè)置一個(gè)“存盤”按鈕的提示代碼。
QToolTip::add(saveButton,"Save");
當(dāng)提示字符出現(xiàn)之后,還可以在狀態(tài)欄顯示更詳細(xì)的文字說(shuō)明。
對(duì)于一些沒(méi)有鼠標(biāo)的設(shè)備(例如那些使用觸點(diǎn)輸入的設(shè)備),就不會(huì)出現(xiàn)鼠標(biāo)的光標(biāo)在窗體上進(jìn)行游動(dòng),這樣就不能激活提示欄。對(duì)于這些設(shè)備也許就需要使用“這是什么”幫助按鈕,或者使用一種狀態(tài)來(lái)表示輸入設(shè)備正在進(jìn)行游動(dòng),例如用按下或者握住的狀態(tài)來(lái)表示現(xiàn)在正在進(jìn)行游動(dòng)。
n “這是什么”幫助按鈕和提示欄有些相似,只不過(guò)前者是要用戶單擊它才會(huì)顯示旁述。在小屏幕設(shè)備上,要想單擊“這是什么”幫助按鈕,具體的方法是,在靠近應(yīng)用的X窗口的關(guān)閉按鈕“x”附近你會(huì)看到一個(gè)“?”符號(hào)的小按鈕,這個(gè)按鈕就是“這是什么”的幫助按鈕。一般來(lái)說(shuō),“這是什么”幫助按鈕按下后要顯示的提示信息應(yīng)該比提示欄要多一些。下面是設(shè)置一個(gè)存盤按鈕的“這是什么”文本提示信息的方法:
QWhatsThis::add(saveButton,"Savethecurrentfile.");
QToolTip和QWhatsThis類提供了可以通過(guò)重新實(shí)現(xiàn)來(lái)獲取更多特殊化行為的虛函數(shù),比如根據(jù)鼠標(biāo)在部件的位置來(lái)顯示不同的文本。
5.動(dòng)作應(yīng)用程序通常提供幾種不同的方式來(lái)執(zhí)行特定的動(dòng)作。比如,許多應(yīng)用程序通過(guò)菜單(Flie->Save)、工具欄(像一個(gè)軟盤的按鈕)和快捷鍵(Ctrl+S)來(lái)提供“Save”動(dòng)作。QAction類封裝了“動(dòng)作”這個(gè)概念。它允許程序員在某個(gè)地方定義一個(gè)動(dòng)作。
下面的代碼實(shí)現(xiàn)了一個(gè)“Save”菜單項(xiàng)、一個(gè)“Save”工具欄按鈕和一個(gè)“Save”快捷鍵,并且均有旁述幫助:
QAction*saveAct=newQAction("Save",saveIcon,"&Save",CTRL+Key_S,this);
connect(saveAct,SIGNAL(activated()),this,SLOT(save()));
saveAct->setWhatsThis("Savesthecurrentfile.");
saveAct->addTo(fileMenu);
saveAct->addTo(toolbar);
為了避免重復(fù),使用QAction可保證菜單項(xiàng)的狀態(tài)與工具欄保持同步,而工具提示能在需要的時(shí)候顯示。禁用一個(gè)動(dòng)作會(huì)禁用相應(yīng)的菜單項(xiàng)和工具欄按鈕。類似地,當(dāng)用戶單擊切換型按鈕時(shí),相應(yīng)的菜單項(xiàng)會(huì)因此被選中或不選。
12.2.6Qt/Embedded對(duì)話框設(shè)計(jì)Qt/Embedded對(duì)話框的設(shè)計(jì)比較復(fù)雜,要使用布局管理自動(dòng)地設(shè)置窗體與別的窗體之間相對(duì)的尺寸和位置,這樣可以確保對(duì)話框能夠最好地利用屏幕上的可用空間,接著還要使用Qt圖形設(shè)計(jì)器可視化設(shè)計(jì)工具建立對(duì)話框。下面就詳細(xì)講解具體的步驟。
1.布局Qt的布局管理用于組織管理一個(gè)父窗體區(qū)域內(nèi)的子窗體。它的特點(diǎn)是可以自動(dòng)設(shè)置子窗體的位置和大小,并可確定出一個(gè)頂級(jí)窗體的最小和缺省的尺寸,當(dāng)窗體的字體或內(nèi)容變化后,它可以重置一個(gè)窗體的布局。
使用布局管理,開(kāi)發(fā)者可以編寫?yīng)毩⒂谄聊淮笮『头较蛑獾某绦?,從而不需要浪費(fèi)代碼空間和重復(fù)編寫代碼。對(duì)于一些國(guó)際化的應(yīng)用程序,使用布局管理,可以確保按鈕和標(biāo)簽在不同的語(yǔ)言環(huán)境下有足夠的空間顯示文本,不會(huì)造成部分文字被剪掉。
布局管理提供部分用戶接口組件,例如輸入法和任務(wù)欄變得更容易。我們可以通過(guò)一個(gè)例子說(shuō)明這一點(diǎn),當(dāng)Qtopia的用戶輸入文字時(shí),輸入法會(huì)占用一定的文字空間,應(yīng)用程序這時(shí)也會(huì)根據(jù)可用屏幕尺寸的變化調(diào)整自己。
Qtopia的布局管理示例如圖12.11所示。
(1)內(nèi)建布局管理器
Qt提供了3種用于布局管理的類:QHBoxLayout、QVBox-
Layout和QGridLayout。
n QHBoxLayout布局管理把窗體按照水平方向從左至右排成一行。
n QVBoxLayout布局管理把窗體按照垂直方向從上至下排成一列。
n QGridLayout布局管理以網(wǎng)格的方式來(lái)排列窗體,一個(gè)窗體可以占據(jù)多個(gè)網(wǎng)格。
它們的示例如圖12.12所示。
在多數(shù)情況下,Qt的布局管理器為其管理的部件挑選一個(gè)最適合的尺寸以便窗口能夠平滑地縮放。如果其缺省值不合適,開(kāi)發(fā)者可以使用以下機(jī)制微調(diào)布局:
n 設(shè)置一個(gè)最小尺寸、一個(gè)最大尺寸,或者為一些子部件設(shè)置固定的大小。
圖12.123種布局管理類示意圖
n 設(shè)置一些延伸項(xiàng)目或間隔項(xiàng)目,延伸或間隔項(xiàng)目會(huì)填充空余的布局空間。
n 改變子部件的尺寸策略。通過(guò)調(diào)用QWidget::setSizePolicy(),程序員可以仔細(xì)調(diào)整子部件的縮放行為。子部件可以設(shè)置為擴(kuò)展、收縮、保持原大小等狀態(tài)。
n 改變子部件的建議大小。QWidget::sizeHint()和QWidget::minimumSizeHint()會(huì)根據(jù)內(nèi)容返回部件的首選尺寸和最小首選尺寸。內(nèi)建部件提供了合適的重新實(shí)現(xiàn)。
n 設(shè)置延伸因子。延伸因子規(guī)定了子部件的相應(yīng)增量,比如,2/3的可用空間分配給部件A而1/3分配給B。
(2)布局嵌套。
布局可以嵌套任意層。圖12.13顯示了一個(gè)對(duì)話框的兩種大小。
圖12.13一個(gè)對(duì)話框的兩種大小
這個(gè)對(duì)話框使用了3種布局:一個(gè)QVBoxLayout組合了按鈕,一個(gè)QHBoxLayout組合了國(guó)家列表和那組按鈕,一個(gè)QVBoxLayout組合了“Selectacountry”標(biāo)簽和剩下的部件。一個(gè)延伸項(xiàng)目用來(lái)維護(hù)Cancel和Help按鈕間的距離。
下面的代碼創(chuàng)建了對(duì)話框部件和布局:
QVBoxLayout*buttonBox=newQVBoxLayout(6);
buttonBox->addWidget(newQPushButton("OK",this));
buttonBox->addWidget(newQPushButton("Cancel",this));
buttonBox->addStretch(1);
buttonBox->addWidget(newQPushButton("Help",this));
QListBox*countryList=newQListBox(this);
countryList->insertItem("Canada");
/*...*/
countryList->insertItem("UnitedStatesofAmerica");
QHBoxLayout*middleBox=newQHBoxLayout(11);
middleBox->addWidget(countyList);
middleBox->addLayout(buttonBox);
QVBoxLayout*topLevelBox=newQVBoxLayout(this,6,11);
topLevelBox->addWidget(newQLabel("Selectacountry",this));
topLevelBox->addLayout(middleBox);
可以看到,Qt讓布局變得非常容易。
(3)自定義布局。
通過(guò)子類化QLayout,開(kāi)發(fā)者可以定義自己的布局管理器。和Qt一起提供的customlayout樣例展示了3個(gè)自定義布局管理器:BorderLayout、CardLayout和SimpleFlow,程序員可以使用并修改它們。
Qt還包括QSplitter,是一個(gè)最終用戶可以操縱的分離器。某些情況下,QSplitter可能比布局管理器更為可取。
為了完全控制,重新實(shí)現(xiàn)每個(gè)子部件的QWidget::resizeEvent()并調(diào)用QWidget::setGeometry(),就可以在一個(gè)部件中手動(dòng)地實(shí)現(xiàn)布局。
2.Qt/Embedded圖形設(shè)計(jì)器Qt圖形設(shè)計(jì)器是一個(gè)具有可視化用戶接口的設(shè)計(jì)工具。Qt的應(yīng)用程序可以完全用源代碼來(lái)編寫,或者使用Qt圖形設(shè)計(jì)器來(lái)加速開(kāi)發(fā)工作。啟動(dòng)Qt圖形設(shè)計(jì)器的方法是:
cdqt-2.3.2/bin
./designer
這樣就可以啟動(dòng)一個(gè)圖形化的設(shè)計(jì)界面,如圖12.14所示。
圖12.14Qt圖形設(shè)計(jì)器界面
開(kāi)發(fā)者單擊工具欄上的代表不同功能的子窗體/組件的按鈕,然后把它拖放到一個(gè)表單(Form)上,這樣就可以把一個(gè)子窗體/組件放到表單上了。開(kāi)發(fā)者可以使用屬性對(duì)話框來(lái)設(shè)置子窗體的屬性,精確地設(shè)置子窗體的位置和尺寸大小是沒(méi)必要的。開(kāi)發(fā)者可以選擇一組窗體,然后對(duì)它們進(jìn)行排列。例如,我們選定了一些按鈕窗體,然后使用“水平排列(layouthorizontally)”選項(xiàng)對(duì)它們進(jìn)行一個(gè)接一個(gè)地水平排列。這樣做不僅使得設(shè)計(jì)工作變得更快,而且完成后的窗體將能夠按照屬性設(shè)置的比例填充窗口的可用范圍。
使用Qt圖形設(shè)計(jì)器進(jìn)行圖形用戶接口的設(shè)計(jì)可以消除應(yīng)用的編譯、鏈接和運(yùn)行時(shí)間,同時(shí)使修改圖形用戶接口的設(shè)計(jì)變得更容易。Qt圖形設(shè)計(jì)器的預(yù)覽功能使開(kāi)發(fā)者能夠在開(kāi)發(fā)階段看到各種樣式的圖形用戶界面,也包括客戶樣式的用戶界面。通過(guò)Qt集成功能強(qiáng)大的數(shù)據(jù)庫(kù)類,Qt圖形設(shè)計(jì)器還可提供生動(dòng)的數(shù)據(jù)庫(kù)數(shù)據(jù)瀏覽和編輯操作。
開(kāi)發(fā)者可以建立同時(shí)包含有對(duì)話框和主窗口的應(yīng)用,其中主窗口可以放置菜單、工具欄、旁述幫助等子窗口部件。Qt圖形設(shè)計(jì)器提供了幾種表單模板,如果窗體會(huì)被多個(gè)不同的應(yīng)用反復(fù)使用,那么開(kāi)發(fā)者也可建立自己的表單模板以確保窗體的一致性。
Qt圖形設(shè)計(jì)器使用向?qū)?lái)幫助人們更快、更方便地建立包含有工具欄、菜單和數(shù)據(jù)庫(kù)等方面的應(yīng)用。程序員可以建立自己的客戶窗體,并把它集成到Qt圖形設(shè)計(jì)器中。
Qt圖形設(shè)計(jì)器設(shè)計(jì)的圖形界面以擴(kuò)展名為“ui”的文件進(jìn)行保存,這個(gè)文件有良好的可讀性,這個(gè)文件可被uic(Qt提供的用戶接口編譯工具)編譯成為C++的頭文件和源文件。qmake工具在它為工程生成的Makefile文件中自動(dòng)包含了uic生成頭文件和源文件的規(guī)則。
另一種可選的做法是在應(yīng)用程序運(yùn)行期間載入ui文件,然后把它轉(zhuǎn)變?yōu)榫邆湓热抗δ艿谋韱?。這樣開(kāi)發(fā)者就可以在程序運(yùn)行期間動(dòng)態(tài)地修改應(yīng)用的界面,而不需重新編譯應(yīng)用,另一方面,也使得應(yīng)用的文件尺寸減小了。
3.建立對(duì)話框Qt為許多通用的任務(wù)提供了現(xiàn)成的包含了實(shí)用的靜態(tài)函數(shù)的對(duì)話框類,主要有以下幾種。
n QMessageBox類:是一個(gè)用于向用戶提供信息或是讓用戶進(jìn)行一些簡(jiǎn)單選擇(例如“yes”或“no”)的對(duì)話框類,如圖12.15所示。
n QProgressDialog類:包含了一個(gè)進(jìn)度欄和一個(gè)“Cancel”按鈕,如圖12.16所示。
n QWizard類:提供了一個(gè)向?qū)?duì)話框的框架,如圖12.17所示。
圖12.15QMessageBox類對(duì)話框圖12.16QProgressDialog類對(duì)話框圖12.17QWizard類對(duì)話框
另外,Qt提供的對(duì)話框還包括QColorDialog、QFileDialog、QFontDialog和QPrintDialog。這些類通常適用于桌面應(yīng)用,一般不會(huì)在Qt/Embedded中編譯使用它們。