(完整word版)QT基礎(chǔ)學(xué)習(xí)知識整理_第1頁
(完整word版)QT基礎(chǔ)學(xué)習(xí)知識整理_第2頁
免費(fèi)預(yù)覽已結(jié)束,剩余23頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、QT基礎(chǔ)學(xué)習(xí)知識整理1. 重要內(nèi)容:1) 信號和槽機(jī)制2) 事件處理機(jī)制3) 布局管理器4) 繪圖5) 網(wǎng)絡(luò)6) 多線程7) 其他(定時(shí)器,中文顯示)2.1 一個(gè)簡單的例子不可免俗的,從最簡單的基本窗口產(chǎn)生開始介紹,窗口標(biāo)題就叫作 First Qt! 好了,請新增一 個(gè)目錄 hello ,并在當(dāng)中使用任一編輯器來編輯一個(gè) hello.cpp 的檔案,內(nèi)容如下:hello.cpp#include #include int main(int argc, char *argv) QApplication app(argc, argv);QLabel *label = new QLabel(Hello

2、!World! Orz.); label-setWindowTitle(FirstQt!);label-resize(200, 50);label-show();return app.exec();要使用 Qt 的組件, 必須含入( include )相對應(yīng)的頭文件, 程序的第一行包含的 QApplication 與 Qlabel頭文件,稍后才可以使用 QApplication 與 QLabel 兩個(gè)組件的定義類別。每個(gè) Qt 窗口程序, 都必須有且只能有一個(gè) QApplication 對象,它管理了整個(gè)應(yīng)用程序所 需的資源 ,QLabel 是 Qt 的圖型組件之一, 繼承自 QWidget

3、,Widget 這個(gè)名稱來自 Window Gadget , 表示可視的使用者接口組件,可接受使用者的動作操作,文字畫面、按鈕、滾動條、工具列甚至容器(Container )等都是一種 WidgetC+程序從 main 開始,再來進(jìn)行 Qt 組件的初始化動作,在第一行中:QApplicati on app(argc, argv);QApplicatio n 負(fù)責(zé)程序的初始、結(jié)束及處理事件(eve nt )的循環(huán)等,并提供基本的窗口外觀,這個(gè)外觀與系統(tǒng)的桌面環(huán)境有關(guān),例如標(biāo)題列的樣式、窗口外觀、系統(tǒng)功能鍵等,在不同的 操作系統(tǒng)桌面環(huán)境下,會有各自不同的外觀,QApplicati on對象接受命令

4、列自變量作為它的自變量,像是如果您沒有設(shè)定窗口標(biāo)題,且會使用執(zhí)行文件的名稱作為窗口標(biāo)題名稱,可以使用的自變量與其作用,可以查詢Qt 在線文件關(guān)于 QApplication類別的說明。接著建立 QLabel 組件, 它用以顯示所指定的文字(在這邊指定了 Hello!World! Orz.),setWi ndowTitle()用以設(shè)定窗口標(biāo)題,如果不設(shè)定標(biāo)題,則會自動以程序的文件名稱作為標(biāo)題,resize()方法用以設(shè)定組件的長、寬,單位是像素( Pixel ), Qt 的組件預(yù)設(shè)是不可視的,所以 要使用 show()方法將之顯示岀來。在最后一行,執(zhí)行 QApplication 的 exec()方

5、法,這將程序的控制權(quán)交給了QApplication ,exec()方法會提供一個(gè)事件處理循環(huán),窗口顯示之后會不斷傾聽(listen )事件,像是鍵盤、鼠標(biāo)等動作所引發(fā)的事件,寫好程序存盤之后,就可以開始進(jìn)行make 的動作,必須先產(chǎn)生 Makefile ,Qt 提供了 qmake程序來協(xié)助建立 Makefile ,它可以自動根據(jù)目前目錄下檔案產(chǎn)生*.pro 的專案檔(project file ):qmake -project然后根據(jù)項(xiàng)目檔產(chǎn)生Makefileqmake接下來就可以進(jìn)行 make:makemake 完成之后,可以在debug 目錄下找到產(chǎn)生的hello.exe 檔案,直接執(zhí)行:h

6、ello如果您要可以在 Windows 下直接 double click就執(zhí)行程序,記得系統(tǒng)環(huán)境變量中要設(shè)定包括 Qt 安裝目錄下的 bin 目錄,執(zhí)行時(shí)的參考畫面如下所示:HeUDiWorHEOrz如果要建構(gòu) release 版本,則使用 make 時(shí)指定-f 與 Makefile 名稱,例如:make -f Makefile.ReleasePATHI* 1 Hrst Qt!回則您可以在 release 數(shù)據(jù)夾下看到建構(gòu)好的檔案。QLabel 支持 HTML 卷標(biāo),如果您把程序改為以下的內(nèi)容:#in elude vQApplicatio n#in elude int main (i nt a

7、rgc, char *argv) QApplicatio n app(argc, argv);QLabel *label = new QLabel(vfo nt color=blueHello!World!Orz.v/fontv/h1);label-setWi ndowTitle(First Qt!); label-resize(200, 50);label-show();retur n app.exec(); 重新建置之后,執(zhí)行結(jié)果將顯示如下:ft. FirstQtlHeUo!WorId!Orz.2.2 信號和槽機(jī)制信號和槽用于對象間的通訊。信號/ /槽機(jī)制是 QtQt 的一個(gè)中心特征并且也

8、許是QtQt 與其它框架非常不同的核心特性。在圖形用戶界面編程中, 我們經(jīng)常希望一個(gè)窗口部件的一個(gè)變化被通知給另一個(gè)窗口部 件。更一般地,我們希望任何一類的對象可以和其它對象進(jìn)行通訊。例如,如果我們正在解析一個(gè) XMLXML 文件,當(dāng)我們遇到一個(gè)新的標(biāo)簽時(shí),我們也許希望通知列表視圖我們正在用來 表達(dá) XMLXML 文件的結(jié)構(gòu)。較老的工具包使用一種被稱作回調(diào)的通訊方式來實(shí)現(xiàn)同一目的?;卣{(diào)是指一個(gè)函數(shù)的指針,所以如果你希望一個(gè)處理函數(shù)通知你一些事件,你可以把另一個(gè)函數(shù)(回調(diào))的指針傳遞給處理函數(shù)。處理函數(shù)在適當(dāng)?shù)臅r(shí)候調(diào)用回調(diào)?;卣{(diào)有兩個(gè)主要缺點(diǎn)。 首先他們不是類型安全的。我們從來都不能確定處理函數(shù)

9、使用了正確的參數(shù)來調(diào)用回調(diào)。其次回調(diào)和處理函數(shù)是非常強(qiáng)有力地聯(lián)系在一起的,因?yàn)樘幚砗瘮?shù)必須知道要調(diào)用哪個(gè)回調(diào)。、connect( Objects signall, Object2?slotl) _ connect) Objectl,signall, Object2, slot2)slotl Sl0t2connecti Object signals, Objectl, slotl)廠ObjEct4、slotlconmectf Objects, signall, Object4, slot3)一個(gè)關(guān)于一些信號和槽連接的摘要圖在 QtQt 中我們有一種可以替代回調(diào)的技術(shù)。我們使用信號和槽。當(dāng)一個(gè)特定

10、事件發(fā)生的 時(shí)候,一個(gè)信號被發(fā)射。QtQt 的窗口部件有很多預(yù)定義的信號,但是我們總是可以通過繼承來加入我們自己的信號。槽就是一個(gè)可以被調(diào)用處理特定信號的函數(shù)。QtQt 的窗口部件又很多預(yù)定義的槽,但是通常的習(xí)慣是你可以加入自己的槽,這樣你就可以處理你所感興趣的信號。信號和槽的機(jī)制是類型安全的:一個(gè)信號的簽名必須與它的接收槽的簽名相匹配。(實(shí)際上一個(gè)槽的簽名可以比它接收的信號的簽名少,因?yàn)樗梢院雎灶~外的簽名。)因?yàn)楹灻且恢碌?,編譯器就可以幫助我們檢測類型不匹配。信號和槽是寬松地聯(lián)系在一起的:一個(gè)發(fā)射信號的類不用知道也不用注意哪個(gè)槽要接收這個(gè)信號。QtQt 的信號和槽的機(jī)制可以保證如果你把一

11、個(gè)信號和一個(gè)槽連接起來,槽會在正確的時(shí)間使用信號的參數(shù)而被調(diào)用。信號和槽可以使用任何數(shù)量、任何類型的參數(shù)。它們是完全類型安全的:不會再有回調(diào)核心轉(zhuǎn)儲(corecore dumpdump)。從 QObjectQObject 類或者它的一個(gè)子類 (比如 QWidgetQWidget 類)繼承的所有類可以包含信號和槽。 當(dāng)對象改變它們的狀態(tài)的時(shí)候,信號被發(fā)送,從某種意義上講,它們也許對外面的世界感興趣。這就是所有的對象通訊時(shí)所做的一切。它不知道也不注意無論有沒有東西接收它所發(fā)射的信號。這就是真正的信息封裝,并且確保對象可以用作一個(gè)軟件組件。例子以下的例子將看到有參數(shù)的 Signal 發(fā)送及 Slot

12、 接受, 并也將介紹 Qt 組件的 parent/child 關(guān)系,這個(gè)程序?qū)⒔⒁粋€(gè)LCD 數(shù)字顯示組件,以及一個(gè)拉桿組件,LCD 數(shù)字將反應(yīng)目前拉桿的Objectlsignallsignal2Objects1signallC Object3signallslotlSlot2SlOt3進(jìn)度:#include #include #include #includeint main(int argc, char *argv) QApplication app(argc, argv);QWidget *parent = new QWidget; parent-setWindowTitle(Signa

13、l & Slot);parent-setMinimumSize(240, 140); parent-setMaximumSize(240, 140);QLCDNumber *lcd = new QLCDNumber(parent); lcd-setGeometry(70, 20, 100,30);QSlider *slider = new QSlider(Qt:Horizontal, parent); slider-setRange(0, 99);slider-setValue(0); slider-setGeometry(70, 70, 100, 30);QObject:connec

14、t(slider, SIGNAL(valueChanged(int), lcd,SLOT(display(int);parent-show();return app.exec();在 Qt 中建立 Widget 時(shí), 要建立在 heap 區(qū)(即以 new 的方式), Qt 會自動管理 pare nt 下 child 的 delete ,讓您不用親自管理具有 parent/child 關(guān)系的 Widget 建構(gòu)與刪除,這可以避 免 memory leak ,您要 delete 的只有那些沒有 parent 的對象,如果您將對象建立在 stack 區(qū), 程序?qū)⒖赡軙绣e誤發(fā)生。QWidget 是

15、Qt 中所有使用者圖形接口組件的父類別, 可在屏幕上繪制自身, 可接受鼠標(biāo)、鍵盤等接口操作,一個(gè) QWidget 可以指定它的 parent 為哪個(gè)組件,而這也表示 child 可顯示的 范圍將是在 parent 之內(nèi), parent沒有顯示的話, 子組件也不會顯示 。沒有指定 parent 的 QWidget 是一個(gè)獨(dú)立窗口( window)。在程序中建立了一個(gè)QWidget 實(shí)例,并設(shè)定它的標(biāo)題名稱,以及可拉動的最大(setMaximumSize )最小(setMinimumSize )尺寸,由于都設(shè)定為240X140 像素大小,所以這個(gè)窗口就變?yōu)椴豢勺儎哟笮〉牧?,也可以只使用一個(gè)setF

16、ixedSize()方法來設(shè)定:QWidget *parent = new QWidget;parent-setWindowTitle(Signal & Slot);pare nt-setMi ni mumSize(240, 140);pare nt-setMaximumSize(240, 140);這個(gè) QWidget 沒有指定 pare nt ,所以它是一個(gè)獨(dú)立窗口,接下來的 QLCDNumbe 實(shí)例建立時(shí),指定了這個(gè) QWidget 為它的 pare nt,所以 QLCDNumbe 被置入了 QWidget 之中成為 child,可顯 示的范圍限制在 pare nt 的邊界大小之

17、中,它在parent 中的位置為 X: 70、丫:20,長為 100、寬為 30 ( setGeometry():QLCDNumber *lcd = new QLCDNumber(pare nt);lcd-setGeometry(70, 20, 100, 30);接下來的 QSlider 實(shí)例在建立時(shí),也指定了這個(gè) QWidget 為它的 pare nt ,程序中設(shè)定 QSlider 為水平拉桿(Qt: Horizontal ),可拉動的數(shù)值范圍為 0 到 99( setRange(),目前拉桿光標(biāo) 值為 0 (setValue(),而它在 pare nt 中的位置為 X: 70、Y: 70,

18、長為 100、寬為 30:QSlider *slider = new QSlider(Qt:Horizo ntal, pare nt); slider-setRange(0, 99);slider-setValue(0); slider-setGeometry(70, 70, 100, 30);當(dāng)您拉動 QSlider 的光標(biāo),造成光標(biāo)值變動時(shí)會發(fā)岀valueChanged(int)Signal ,參數(shù) int表示 Signal 帶有一個(gè)整數(shù)值,在這表示QSlider 的游標(biāo)值一并被發(fā)岀,QLCDNumbe 的display(int) Slot接受 Signal 所帶來的整數(shù)值,可以在QLCD

19、Numbe 顯示數(shù)字:QObject:co nn ect(slider, SIGNAL(valueCha nged(i nt), led,SLOT(display(i nt);一個(gè)程序執(zhí)行時(shí)的參考畫面如下所示:注意:1.Signal 與 Slot 的簽名基本上要相同,但若 Signal 的參數(shù)多于 Slot 的參數(shù),則額外的參數(shù)會被Slot 忽略。Signal & Slot2.一個(gè) Signal 可以關(guān)聯(lián)多個(gè) Slot 函數(shù)。3.Signal 也可以和 Signal 關(guān)聯(lián)。(消息 消息)4.Qt 管理的對象必須繼承 QObject 類別, 以提供 Qt 對象的 Meta 訊息, 若要實(shí)

20、作 Signal 與 Slot 機(jī)制, 則必須包括 Q_OBJECTQ_OBJECT宏,moc 會處理 Qt 的 C+擴(kuò)充(Meta-Object System ),使用 moc 讀取 C+ 標(biāo)頭檔案,若發(fā)現(xiàn)類別定義中包括Q_OBJECT 宏,就會產(chǎn)生 Qt meta-object 相關(guān)的 C+程序代碼。5.QTQT CreatorCreator 開發(fā) QTQT 程序時(shí)候,請確保信號和槽函數(shù)書寫正確。在編譯時(shí),編譯器不會對 信號和槽函數(shù)中的書寫錯誤做出判斷) 。例如 : :connect(OBJECT1 , SIGNAL (signalName(bool), OBJECT2 , SLOT (s

21、lotName(bool);2.4 事件處理機(jī)制1) 事件類型及處理者執(zhí)行 QApplication 的 exec() 方法之后, 應(yīng)用程序會進(jìn)入事件循環(huán)來傾聽?wèi)?yīng)用程序的事件,事件來源通常是窗口系統(tǒng), 例如使用者的鼠標(biāo)事件或鍵盤事件, 事件來源可以是 Qt 應(yīng)用程序事件本身, 例如 QTimerEvent (定時(shí)器),事件來源也可以是使用者自定義的事件,通過QApplicaiton 的 sendEvent() 或 postEvent() 來發(fā)送。當(dāng)事件發(fā)生時(shí),Qt 為之建立事件實(shí)例,QEvent 是 Qt 中所有事件的基類,Qt 所建立的事件實(shí)例為QEvent的子類別實(shí)例,并將之傳送給 QOb

22、ject 子類實(shí)例的 event() 函式, event() 這個(gè)函式本身通常不直接處理事 件,而是基于所傳送的事件類型,分派給處理特定類型的事件處理者(Event Handler )。QEvent 是 Qt 中所有事件的基礎(chǔ)類別,最常見的事件類型皆為其子類別, 像是鼠標(biāo)事件的 QMouseEvent、鍵盤事件的 QKeyEvent、縮放事件的 QResizeEvent 等,這些子類別事件皆加入其特定的函數(shù),像是鼠標(biāo)事件的 x()、y()函數(shù)指岀發(fā)生鼠標(biāo)事件時(shí),鼠標(biāo)光標(biāo)的x、y 坐標(biāo),鍵盤事件的 key()函數(shù)可以取得目前所按下的按鍵常數(shù)。以圖型組件來說,通常我們會繼承 QWidget 或其子

23、類,并重新定義事件的處理函數(shù), QWidget 定義了像 是keyPressEvent() 、 keyReleaseEvent() 、 mouseDoubleClickEvent() 、 mouseMoveEvent () 、 mousePressEvent() 、mouseReleaseEvent() 等事件處理函數(shù),并接受 QEvent 的特定子類別實(shí)例作為自變量, 只要根據(jù)想要處理的事件重新定義對應(yīng)的函式即可進(jìn)行事件處理。以下則是個(gè)簡單的事件處理示范,繼承了 QLabel 并重新定義了相關(guān)的事件處理者,當(dāng)鼠標(biāo)移動、按下或 放開時(shí),顯示鼠標(biāo)光標(biāo)的所在位置:#include #include

24、 #include #include class EventLabel : public QLabel protected:void mouseMoveEvent(QMouseEvent *event);void mousePressEvent(QMouseEvent *event);void mouseReleaseEve nt(QMouseEve nt *eve nt);;void Eve ntLabel:mouseMoveEve nt(QMouseEve nt *eve nt) QStri ng msg;msg.spri ntf(Move: (%d, %d)v/ce nter, eve

25、nt-x(), eve nt-y();this-setText(msg);void Eve ntLabel:mousePressEve nt(QMouseEve nt *eve nt) QStri ng msg;msg.spri ntf(Press: (%d, %d), eve nt-x(), eve nt-y();this-setText(msg);void Eve ntLabel:mouseReleaseEve nt(QMouseEve nt *eve nt) QStri ng msg;msg.spri ntf(Release: (%d, %d), eve nt-x(), eve nt-y

26、();this-setText(msg);int main (i nt argc, char *argv) QApplicatio n app(argc, argv);Eve ntLabel *label = new Eve ntLabel;label-setWi ndowTitle(MouseEve nt Demo);label-resize(300, 200);label-show();retur n app.exec();執(zhí)行時(shí)的參考畫面如下所示:注意:Qt 的事件跟 Signal 、Slot 機(jī)制是不同的。 Signal 與 Slot 的機(jī)制是同步的( Synchronous ), S

27、ignal 是由對象發(fā)出的,使用 QObject 的 connect() 連接對象上定義的 Slot 來立即處理。 Qt 的事件可以是異步的(Asynchronous )的,QT 使用一個(gè)事件隊(duì)列來維護(hù),新的事件產(chǎn)生時(shí)基本上會被排到隊(duì)列的尾端,前一個(gè)事 件處理完成,再從隊(duì)列的前端取出下一個(gè)隊(duì)列來處理,必要的時(shí)候,Qt 的事件也可以是同步的,而事件還可以使用 事件過濾器 進(jìn)行過濾處理。2)事件類型及處理者不同類型的事件,都有對應(yīng)的事件處理函數(shù),它們接受QEvent 的特定子類別實(shí)例作為自變量,像是下例中 mousePressEvent() 事件處理函數(shù)上的 QMouseEvent ,您可以針對事

28、件的某些狀 況作特定處理, 而其它未處理的狀況, 則呼叫父類別對應(yīng)的的事件處理函式, 讓父類別預(yù)先定義 的事件處理可以完成: voidCustomLabel:mousePressEvent(QMouseEvent *event) if (event-button() = Qt:LeftButton) / 處理左鍵按下/ . else /由父類別所定義的事件處理函式來事件QLabel:mousePressEvent(event);void CustomLabel:mouseReleaseEvent(QMouseEvent *event) / 鼠標(biāo)放開事件處理 .事實(shí)上,每個(gè)可傳遞的事件都有 ac

29、cept () 與 igore () 兩個(gè)方法,用以告知 Qt 應(yīng)用程序,這 個(gè)事件處理者是否接受或忽略此一事件, 如果事件處理者中呼叫事件的 accept() ,則事件不會 再進(jìn)一步傳播,若呼叫了 ignore(),則 Qt 應(yīng)用程序會嘗試尋找另一個(gè)事件的接受者,您可以藉由 isAccepted() 方法得知事件是否被接受。一般來說, 除了 QCloseEvent 之外, 很少直接呼叫 accept() 或 ignore() ,如果您接受事件, 則在事件處理者當(dāng)中實(shí)作對事件的處理(如上例的if 陳述句),如果您不接受事件,則直接呼叫父類別的事件實(shí)作(如上例的 else 陳述句), 對于 QW

30、idget 來說, 預(yù)設(shè)的實(shí)作是: void QWidget:keyPressEvent(QKeyEvent*event) event-ignore();由于 QWidget 預(yù)設(shè)的實(shí)作是呼叫 ignore() ,這讓事件可以向父組件傳播。QCloseEvent 則建議直接呼叫 accept() 與 ignore() , accept() 方法會繼續(xù)關(guān)閉的操作, ignore() 則會取消關(guān)閉的操作:void MainWindow:closeEvent(QCloseEvent *event) if (continueToClose() event-accept(); else event-ig

31、nore();QObject 的 event() 方法通常用于分派事件,但在某些情況下,您希望在事件分派給其它事 件處理者之前,先行作一些處理,則可以重新定義 event() 方法,例如在窗口程序中, Tab 鍵按 下時(shí)希望其將焦點(diǎn)移至下一個(gè)圖型組件, 而不是直接讓目前焦點(diǎn)的圖形組件直接處理 Tab 鍵,則 您可以在繼承 QWidget 子類別時(shí),重新定義其 event() 方法,例如: boolCustomWidget:event(QEvent *event) if (event-type() = QEvent:KeyPress) QKeyEvent *keyEvent = static_c

32、ast(event);if (keyEvent-key() = Qt:Key_Tab) / 處理 Tab 鍵return true;return QWidget:event(event);在執(zhí)行時(shí)期想要知道所取得之 QEvent 類型,可以使用 QEvent 的 type() 方法取得常數(shù)值, 并與 QEvent:Type 作比對。3)事件過濾器Qt 將事件封裝為 QEvent 實(shí)例之后,會呼叫 QObject 的 event() 方法并將 QEvent 實(shí)例傳送給它,在某些 情況下,您希望對象在執(zhí)行 event() 處理事件之前,先對一些事件進(jìn)行處理或過濾,然后再決定是否呼叫 event()

33、 方法,這個(gè)時(shí)候您就可以使用事件過濾器。上面提到的對 QWidget 按鍵事件的 Tab 鍵處理而言,如果您的圖形接口中有很多的組件,每個(gè)圖型組件 都要如當(dāng)中的范例重新定義 event() 方法,顯然是非常沒有效率且沒什么維護(hù)性的方法。您可以自定義一個(gè)對象繼承 QObject (或其子類別),重新定義它的 eventFilter () 方法,例如您自定 義了一個(gè)FilterObject ,您希望 Tab 鍵可以用來將焦點(diǎn)轉(zhuǎn)移至下一個(gè)子組件: bool FilterObject:eventFilter(QObject *object, QEvent*event) if(event-type()

34、= QEvent:KeyPress) QKeyEvent *keyEvent = static_cast(event);if (keyEvent-key() = Qt:Key_Tab) / 處理 Tab 鍵return true;return false;eventFilter() 的 object 參數(shù)表示事件發(fā)生的來源對象,eventFilter() 若傳回 false , 則安裝該事件過 濾器的對象之 event()就會繼續(xù)執(zhí)行,若傳回 true ,則安裝該事件過濾器的對象之 event() 方法就不會被執(zhí) 行,由此進(jìn)行事件的攔截處理。要為指定的對象安裝事件過濾器,可以使用對象的 ins

35、tallEventFilter () 方法,例如: QLineEdit *nameEdit = new QLineEdit;QLineEdit *addressEdit = new QLineEdit;FilterObject filter = new FilterObject;nameEdit-installEventFilter(filter); addressEdit-installEventFilter(filter);您也可以將事件過濾器安裝在 QApplication ,在任何的事件發(fā)生后呼叫每個(gè)對象的 event() 方法之前, 會先經(jīng)過事件過濾器,這給您更多控制應(yīng)用程序事件的能

36、力。Qt 的事件循環(huán)與 sendEvent() 方法會呼叫 QCoreApplication ( QApplication 的父類別)的 notify() 以 分派事件,如果您想要完全控制 Qt 應(yīng)用程序的事件,則可以重新定義 notify() 方法??梢钥闯?Qt 事件處理的五個(gè)層次:重新定義事件處理者、重新定義2.4 布局管理器設(shè)計(jì)窗口程序的人都知道, 在窗口程序中最麻煩也最難的就是版面配置, 每次都為了組件的 位置擺放在傷腦筋,當(dāng)然我們可以通過 setGeometry() 來設(shè)定 Widget 于 parent 中的 XY 位置與 長寬,但這樣在您窗口縮放時(shí),當(dāng)中的組件位置并不會適當(dāng)?shù)淖?/p>

37、我調(diào)整大小、位置(或像是字號 自動調(diào)整之類的),以配合窗口縮放展現(xiàn)適當(dāng)?shù)挠^感。所以窗口程序的解決方案都會提供一些現(xiàn)成的版面配置方式,讓您可以不必自行配置組件位 置,以下直接看例子,使用 QHBoxLayout 進(jìn)行組件的版面配置, 這可以讓您以水平的方式來擺放 組件:#include #include #include #i nclude #i nclude int main (i nt argc, char *argv) QApplicatio n app(argc, argv);QWidget *window = new QWidget;win dow-setWi ndowTitle(QH

38、BoxLayout);win dow-resize(250, 50);QLCDNumber *lcd = new QLCDNumber;QSpi nBox *sp in Box = new QSpi nBox;spi nBox-setRa nge(0, 99);event() 方法、為個(gè)別對象安裝事件過濾器、為 QApplication 安裝事件過濾器,重新定義QCoreApplication的 notify() 方法。QObject:connect(spinBox, SIGNAL(valueChanged(int),lcd, SLOT(display(i nt);QHBoxLayout *l

39、ayout = new QHBoxLayout;layout-addWidget(spi nBox);layout-addWidget(lcd);win dow-setLayout(layout);wi ndow-show();retur n app.exec();這個(gè)程序中,沒有自行設(shè)定組件的pare nt/child關(guān)系,也沒有設(shè)定組件的大小、位置,而直接使用 QHBoxLayout 將組件加入,這會把 QHBoxLayout 及其管理的組件設(shè)成程序中window 的子組件,并依 QHBoxLayout 版面配置策略自動水平配置組件,一個(gè)執(zhí)行的的畫面如下所示組件會自動填滿窗口,如果您拉動窗

40、口,則當(dāng)中的組件也會適當(dāng)?shù)淖儎哟笮?QHBoxLayout 中組件的加入順序,就是水平配置由左至右顯示的順序,至于QVBoxLayout 的使用方式則與 QHBoxLayout 類似,再來一個(gè)例子改用QVBoxLayout 來配置組件位置:#in clude #include #in elude #i nclude #in elude int main (i nt argc, char *argv) QAppIicatio n app(argc, argv);QWidget *window = new QWidget;win dow-setWi ndowTitle(QVBoxLayout);w

41、i ndow-resize(240, 100);QLCDNumber *lcd = new QLCDNumber;QSlider *slider = new QSIider(Qt:Horizontal); slider-setRange(0, 99);slider-setValue(0);QObject:co nn ect(slider, SIGNAL(valueCha nged(i nt), lcd, SLOT(display(i nt);QVBoxLayout *layout = new QVBoxLayout(wi ndow); layout-addWidget(lcd);layout-

42、addWidget(slider);wi ndow-show();retur n app.exec();程序中可以看到,在建立版面配置對象時(shí),也可以直接指定要實(shí)施版面配置的對象。拉動時(shí)的畫面如下所示:2.5 繪圖QPainter 、 QPaintEngine 、 QPaintDevice 組成了 Qt 的繪圖系統(tǒng), QPainter 提供低階的繪 圖 API ,在內(nèi)部使用QPaintEngine 作為接口, 在 QPaintDevice 進(jìn)行繪圖, 只要是 QPaintDevice 的子類別, 就可以建立 QPainter 在其上進(jìn)行圖形繪制, 像是 QWidget 、QImage、QPict

43、ure 、QPrinter 等都是 QPaintDevice 的子類別。建立 QPainter 的方式如下,其中 qPainterDevice 是個(gè)指向 QPaintDevice 子類別的名稱: QPainterpainter(qPainterDevice);若是圖形組件,通常會重新定義 QWidget 的 paintEvent() ,當(dāng)繪圖裝置( Paint Device ) 需要重繪時(shí), 就會發(fā)出QPaintEvent 并分派給這個(gè)方法來處理事件, 例如組件出現(xiàn)、 被覆蓋又重 現(xiàn)時(shí),您也可以呼叫 repaint() 或 update() ,這也會執(zhí)行 paintEvent() 。QPain

44、ter 提供各種繪制圖形的 API ,從基本的線繪制、 方塊、 矩形、圓形、 漸層到復(fù)雜的圖片等,QPainter 都有提供相對應(yīng)的API,使用的方式參考 QT 幫助文檔。在這邊基本上要先了解的是,(Font )。QPai nter 的三個(gè)基本設(shè)定:筆觸(Pen)、筆刷(Brush )與字型筆觸在 Qt 中是以 QPen 作代表,用來于繪制線條或輪廓時(shí)決定樣式,像是顏色、筆寬、轉(zhuǎn)折、線 條樣式(實(shí)線、曲線、點(diǎn)狀線之類的樣式)等。筆刷在 Qt 中是以 QBrush 作代表,用來于繪制矩形、 圓形、 扇形等幾何圖形時(shí)決定樣式,像是顏 色、填滿樣式、漸層等。以下先看一個(gè)簡單的程序,了解一下QPa i

45、n ter 的幾個(gè) API,以及 QPen QBrush 的使用:#include #include #include class PainterWidget : public QWidget protected:/ 重新定義 paintEvent() 事件處理void paintEvent(QPaintEvent*);/ 實(shí)作事件處理void PainterWidget: paintEvent (QPaintEvent *event) / 建立 QPainterQPainter painter(this);/ 設(shè)定筆觸為點(diǎn)狀線painter.setPen(Qt:DotLine);/ 指定 x

46、、 y、 width 、height 繪制線條painter.drawLine(10, 10, 100, 10);/ 設(shè)定筆刷為藍(lán)色、對角斜線樣式 painter.setBrush(QBrush(Qt:blue, Qt:BDiagPattern);/ 指定 x、 y、 width 、height 繪制矩形 painter.drawRect(10, 20, 100, 50);/ 設(shè)定線形漸層, x1,y1 為起點(diǎn), x2,y2 為終點(diǎn) QLinearGradient gradient(50, 100, 300, 350);/ 設(shè)定漸層顏色過渡 gradient.setColorAt(0.0, Q

47、t:white); gradient.setColorAt(0.2, Qt:green);gradient.setColorAt(1.0, Qt:black);/ 以漸層對象建立筆刷 painter.setBrush(QBrush(gradient);/ 繪制圓角矩形 painter.drawRoundRect(10, 80, 100, 50);/ 繪制扇形,單位為 1/16 角度,下例為 45 度 到 300 度 painter.drawPie(10, 150, 100, 50, 45* 16, 300 * 16);/ 繪制圖片painter.drawPixmap(150, 10, QPix

48、map(caterpillar.jpg);/ 繪制填滿圖形painter.drawTiledPixmap(150, 170, 185, 25, QPixmap(caterpillar_smaill.gif);int main(int argc, char *argv) QApplication app(argc, argv);PainterWidget pWidget;pWidget.setWindowTitle(QPainter);pWidget.resize(350, 200);pWidget.show();return app.exec();2.6 網(wǎng)絡(luò)QHttp 是 Qt 所提供有關(guān)網(wǎng)

49、絡(luò)的高階 API,可以協(xié)助您進(jìn)行 HTTP 協(xié)議的進(jìn)行,QHttp 發(fā)岀請求時(shí) 是異步的,請求的過程中會發(fā)岀相關(guān)的 Signal,您可以用 Slot 來接收這些 Signal ,并進(jìn)行相關(guān) 的處理。以下先示范一個(gè)最基本的QHttp 使用,程序?qū)⒃O(shè)計(jì)一個(gè)HttpGet 類別:* HttpGet.h#ifndef HTTPGET_H #defi ne HTTPGET_H#include class QUrl;class QHttp;class QFile;class HttpGet : public QObject Q_OBJECT public:HttpGet(QObject *pare nt

50、= 0); void downloadFile(const QUrl &url);sig nals:void fini shed();private slots:void don e(bool error);執(zhí)行的結(jié)果如下所示:亙QPainterprivate:QHttp *http;QFile *file;#en dif這個(gè) HttpGet 可以讓您指定檔案的URL 地址,以 HTTP 方式取得檔案并儲存在本地端,URL在 Qt 中以 QUrl 代表,當(dāng)檔案下載完成時(shí),會發(fā)岀finished()的 Signal,當(dāng) QHttp 所排定的全部請求完成時(shí),會發(fā)岀done()的 Signa

51、l,HttpGet 類別中自定的 Slot,就是用來接收 QHttp 的done() Signal以進(jìn)行相關(guān)處理,這可以在HttpGet 的實(shí)作看到:* HttpGet.cpp#i nclude #i nclude #i nclude #include HttpGet.husing n amespace std;HttpGet:HttpGet(QObject *parent) : QObject(parent) http = new QHttp(this);connect(http, SIGNAL(done(bool), this, SLOT(done(bool);void HttpGet:d

52、ownloadFile(const QUrl &url) QFileInfo fileInfo(url.path();QStri ng fileName = fileI nfo.fileName();if (fileName.isEmpty() fileName = in dex.html;file = new QFile(fileName);if (!file-open(QIODevice:WriteOnly) cerr Un able to save the file setHost(url.host(), url.port(80);http-get(url.path(), fil

53、e);http-close();void HttpGet:d on e(bool error) if (error) cerr Error: errorStri ng() en dl; else cerr File downloaded as fileName()close();delete file;file = 0;emit fini shed();要使用 Qt 的網(wǎng)絡(luò)相關(guān)類別,必須引進(jìn) QtNetwork,并且必須在.pro 檔案中,加入以下這行以在建構(gòu)過程中使用Qt 網(wǎng)絡(luò)模塊:QT += n etwork當(dāng)呼叫 HttpGet 類別的 downloadFile() 方法時(shí),程序中使用

54、QUrl 的 path()來取得路徑訊 息,如果路徑訊息中沒有包括文件名,就使用預(yù)設(shè)的index.html作為請求的對象及下載后存盤時(shí)的檔名,要使用 QHttp 來請求檔案時(shí),必須使用setHost () 來設(shè)定主機(jī)及連接端口信息,接著使用 get()方法發(fā)岀請求,并告知下載的檔案要到用哪個(gè)QFile 來存盤。當(dāng) QHttp 所有請求處理完畢后,會發(fā)岀 done()的 Signal ,程序中將之連接至 HttpGet 的 done() 來處理,處理完成之后,再發(fā)岀finished() 的 Signal。以下寫個(gè)簡單的程序來測試HttpGet : main .cpp#i nclude vQCor

55、eApplicati on#i nclude #include HttpGet.h#i nclude using n amespace std;int main (i nt argc, char *argv) QCoreApplicatio n app(argc, argv);HttpGet getter;getter.dow nloadFile(QUrl(http:/caterpillar.o nlyfun.n et/i ndex.html);QObject:co nn ect(&getter,SIGNAL(fi ni shed(),& app, SLOT(quit();re

56、tur n app.exec();程序中將 HttpGet 的 finished()的 Signal 連接至 QCoreApplication 的 quit(),如此當(dāng)下載檔案完成后,可以直接關(guān)閉應(yīng)用程序。Qt 的 QHttp 與 QFtp 在使用上有許多類似的地方,可以在以上的范例看到一些特性,以下再整理 出相關(guān)特性:*非阻斷行為,請求是異步的。*您可以排定一連串的請求,每個(gè)請求都有一個(gè)CommandD, QHttp 的 requestStarted()與 requestFi ni shed()等 Sig nal 會帶有請求的 Comma nd ID,您可以用以追蹤請求的執(zhí)行。*在數(shù)據(jù)傳輸?shù)?/p>

57、過程中,有相關(guān)的Signal 可以追蹤進(jìn)度,像是 QHttp 的dataReadProgress() 、dataSendProgress() 等 Signal。*支持 QIODevice 的寫入(下載)與讀取(上傳),還有以 QByteArray 為基礎(chǔ)的 API。QHttp 還可以針對請求標(biāo)頭、 HTTPS 等加以處理, 在 Qt 的在線文件中, 有個(gè) QHttp 的范例 Http Example,MQHttp 的使用有更完整的示范。2.7 多線程1) Qthread下面這個(gè)程序是個(gè)簡單的程序,您可以看到如何繼承QThread、重新定義 run()方法及如何啟動線程,程序中將以兩個(gè)線程同時(shí)對

58、一個(gè)QPixmap 畫圓,顯示兩個(gè)同時(shí)進(jìn)行的流程:* CircieThread.h在 Qt 中要實(shí)現(xiàn)線程功能,可以繼承 個(gè)線程,則建構(gòu)這個(gè)自訂的對象,并執(zhí)行QThread 類別,并重新定義start()方法。run()方法,之后要啟動一#ifndef CIRCLETHREAD_H #define CIRCLETHREAD H #i nclude class QLabel;class QPixmap;class CircleThread :public QThread Q_OBJECTpublic:CircleThread(QLabel *label, QPixmap *pixmap, int

59、y);protected:void run();private:QLabel *label;QPixmap *pixmap;int y;#en difCircleThread 建構(gòu)函式中,QPixmap 是 QLabel 將顯示的圖片,而 y 值是畫圓時(shí)的位置,CircleThread 實(shí)作如下:* CircleThread.cpp#include CircleThread.h#in clude #i nclude #in clude CircleThread:CircleThread(QLabel *label, QPixmap *pixmap, int y) this-label =lab

60、el;this-pixmap = pixmap;this-y = y;void CircleThread:ru n() QPai nter pai nter(pixmap);for(int i = 10; i setPixmap(*pixmap);QThread:msleep(500);在 run()方法中,將在 QPixmap 上建構(gòu) QPainter,然后依序畫 10 個(gè)圓,接著將畫好的 QPixmap 再次設(shè)置給QLabel ,以重新在 QLabel 上顯示新的繪制畫面。QThread:msleep() 可以令目前的線程暫停所設(shè)置的毫秒數(shù)。您可以撰寫以下的程式來使用CircleThread : mai n.cpp#in clude vQApplicat

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論