QT框架的C編程_第1頁
QT框架的C編程_第2頁
QT框架的C編程_第3頁
QT框架的C編程_第4頁
QT框架的C編程_第5頁
已閱讀5頁,還剩34頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、1、 Qt概述1、關(guān)于QtQt是Trolltech公司的一個產(chǎn)品。Qt是一個多平臺的C+圖形用戶界面應(yīng)用程序框架。它提供給應(yīng)用程序開發(fā)者建立圖形用戶界面應(yīng)用程序所需的所有功能。Qt是完全面向?qū)ο蟮模苋菀讛U(kuò)展,并且允許真正的組件編程。自從1996年早些時候,Qt進(jìn)入商業(yè)領(lǐng)域,它已經(jīng)成為全世界范圍內(nèi)數(shù)千種成功的應(yīng)用程序的基礎(chǔ)。Qt也是流行的Linux桌面環(huán)境KDE 的基礎(chǔ)。(KDE是所有主要的Linux發(fā)行版的一個標(biāo)準(zhǔn)組件) Qt支持下述平臺: MS/Windows - 95、98、NT 4.0、ME、和2000Unix/X11 - Linux、Sun Solaris、HP-UX、Compaq

2、 Tru64 UNIX、IBM AIX、SGI IRIX和其它很多X11平臺Macintosh - Mac OS X Embedded - 有幀緩沖(frame buffer)支持的Linux平臺。2、Qt版本信息 Qt被按不同的版本發(fā)行: Qt企業(yè)版和Qt專業(yè)版:提供給商業(yè)軟件開發(fā)。它們提供傳統(tǒng)商業(yè)軟件發(fā)行版并且提供免費升級和技術(shù)支持服務(wù)。企業(yè)版比專業(yè)版多一些擴(kuò)展模塊。 Qt自由版:是Qt僅僅為了開發(fā)自由和開放源碼軟件 提供的Unix/X11版本。在Q公共許可證和GNU通用公共許可證下,它是免費的。Qt/嵌入式自由版:是Qt為了開發(fā)自由軟件提供的嵌入式版本。在GNU通用公共許可證下,它是免費

3、的。下表是關(guān)于Qt在Windows環(huán)境下各個版本的區(qū)別。(Qt為Windows只提供了專業(yè)版和企業(yè)版,不過自由版本的Qt仍然可以在Windows環(huán)境下使用)組成模塊自由版專業(yè)版企業(yè)版Qt的基本模塊(工具、核心、窗口部件、對話框)與平臺無關(guān)的Qt圖形用戶界面工具包和應(yīng)用類XXXQt設(shè)計器可視化的Qt圖形用戶界面的生成器XXX圖標(biāo)視圖模塊幾套圖形用戶交互操作的可視化效果。XX工作區(qū)模塊多文檔界面(MDI)支持XXOpenGL 三維圖形模塊在Qt中集成了OpenGLX網(wǎng)絡(luò)模塊一些套接字,TCP,FTP和異步DNS查詢并與平臺無關(guān)的類X畫布模塊為可視化效果,圖表和其它而優(yōu)化的二維圖形領(lǐng)域X表格模塊靈活

4、的,可編輯的表格/電子表格XXML模塊通過SAX接口和DOM Level 1的XML解析器XSQL模塊SQL數(shù)據(jù)庫訪問類X3、Qt的組成Qt提供了一組范圍相當(dāng)廣泛的C+類庫,并包含了幾種命令行和圖形界面的工具,有效地使用這些工具可以加速開發(fā)過程。Qt Designer:Qt設(shè)計器。用來可視化地設(shè)計應(yīng)用程序界面。Qt Linguist:Qt語言學(xué)家。用來翻譯應(yīng)用程序。以此提供對多種語言的支持。Qmake:使用此工具可以由簡單的、與平臺無關(guān)的工程文件來生成編譯所需的Makefile。Qt Assistant:關(guān)于Qt的幫助文件。類似于MSDN。可以快速地發(fā)現(xiàn)你所需要的幫助。moc:元對象編譯器。u

5、ic:用戶界面編譯器。在程序編譯時被自動調(diào)用,通過ui_*.h文件生成應(yīng)用程序界面。qembed:轉(zhuǎn)換數(shù)據(jù),比如,將圖片轉(zhuǎn)換為C+代碼。4、Qt的安裝安裝的過程對于不同的Qt平臺是不同的。在Windows環(huán)境下安裝Qt,需要先安裝MinGW。MinGW,即 Minimalist GNU For Windows。它是一些頭文件和端口庫的集合,該集合允許人們在沒有第三方動態(tài)鏈接庫的情況下使用 GCC(GNU Compiler C)產(chǎn)生 Windows32 程序。在基本層,MinGW 是一組包含文件和端口庫,其功能是允許控制臺模式的程序使用微軟的標(biāo)準(zhǔn)C運行時間庫(MSVCRT.DLL),該庫在所有的

6、 NT OS 上有效,在所有的 Windows 95 發(fā)行版以上的 Windows OS 有效,使用基本運行時間,你可以使用 GCC 寫控制臺模式的符合美國標(biāo)準(zhǔn)化組織(ANSI)程序,可以使用微軟提供的 C 運行時間擴(kuò)展。該功能是 Windows32 API 不具備的。下一個組成部分是 w32api 包,它是一組可以使用 Windows32 API 的包含文件和端口庫。與基本運行時間相結(jié)合,就可以有充分的權(quán)利既使用 CRT(C Runtime)又使用 Windows32 API 功能。實際上 MinGW 并不是一個 C/C+ 編譯器,而是一套 GNU 工具集合。除開 GCC (GNU 編譯器集

7、合) 以外,MinGW 還包含有一些其他的 GNU 程序開發(fā)工具 (比如 gawk bison 等等)。在安裝MinGW之后,再安裝Qt,然后更改一下Windows系統(tǒng)的環(huán)境變量,就可以在Windows環(huán)境下使用Qt了。如果想在VC環(huán)境下使用Qt,那么還需要進(jìn)一步編譯和設(shè)置,或者下載專門用于VC的QT版本。有關(guān)此方面的信息請參考附錄。二、 開始學(xué)習(xí)Qt1、Hello, Qt!我們以一個非常簡單的Qt程序開始Qt的學(xué)習(xí)。我們首先一行行的分析代碼,然后我們將會看到怎樣編譯和運行這個程序。1 #include 2 #include 3 int main (int argc, char *argv )

8、4 5 QApplication app (argc, argv);6 QLabel *label = new QLabel (Hello Qt!);7 label-show ();8 return app. exec ();9 第1行和第2行包含了兩個類的定義:QApplication和QLabel。對于每一個Qt的類,都會有一個同名的頭文件,頭文件里包含了這個類的定義。因此,你如果在程序中使用了一個類的對象,那么在程序中就必須包括這個頭文件。第3行是程序的入口。幾乎在使用Qt的所有情況下,main()函數(shù)只需要在把控制權(quán)轉(zhuǎn)交給Qt庫之前執(zhí)行一些初始化,然后Qt庫通過事件來向程序告知用戶的行

9、為。argc是命令行變量的數(shù)量,argv是命令行變量的數(shù)組。這是一個C/C+特征。它不是Qt專有的,無論如何Qt需要處理這些變量第5行定義了一個QApplication對象App。QApplication管理了各種各樣的應(yīng)用程序的廣泛資源,比如默認(rèn)的字體和光標(biāo)。App的創(chuàng)建需要argc和argv是因為Qt支持一些自己的命令行參數(shù)。在每一個使用Qt的應(yīng)用程序中都必須使用一個QApplication對象,并且在任何Qt的窗口系統(tǒng)部件被使用之前創(chuàng)建此對象是必須的。App在這里被創(chuàng)建并且處理后面的命令行變量(比如在X窗口下的-display)。請注意,所有被Qt識別的命令行參數(shù)都會從argv中被移除(

10、并且argc也因此而減少)。第6行創(chuàng)建了一個QLabel窗口部件(widget),用來顯示“Hello,Qt!”。在Qt和Unix的術(shù)語中,一個窗口部件就是用戶界面中一個可見的元素,它相當(dāng)于Windows術(shù)語中的“容器”加上“控制器”。按鈕(Button)、菜單(menu)、滾動條(scroll bars)和框架(frame)都是窗口部件的例子。窗口部件可以包含其它的窗口部件。例如,一個應(yīng)用程序界面通常就是一個包含了QMenuBar,一些QToolBar,一個QStatusBar和其它的一些部件的窗口。絕大多數(shù)應(yīng)用程序使用一個QMainWindow或者一個QDialog作為程序界面,但是Qt允

11、許任何窗口部件成為窗口。在這個例子中,QLabel窗口部件就是作為應(yīng)用程序主窗口的。第7行使我們創(chuàng)建的QLabel可見。當(dāng)窗口部件被創(chuàng)建的時候,它總是隱藏的,必須調(diào)用show()來使它可見。通過這個特點我們可以在顯示這些窗口部件之前定制它們,這樣就不會出現(xiàn)閃爍的情況。第8行就是main()將控制權(quán)交給Qt。在這里,程序進(jìn)入了事件循環(huán)。事件循環(huán)是一種stand-by的模式,程序會等待用戶的動作(比如按下鼠標(biāo)或者是鍵盤)。用戶的動作將會產(chǎn)生程序可以做出反應(yīng)的事件(也被稱為“消息”)。程序?qū)@些事件的反應(yīng)通常是執(zhí)行一個或幾個函數(shù)。為了簡單起見,我們沒有在main()函數(shù)的結(jié)尾處調(diào)用delete來刪除

12、QLabel對象。這種內(nèi)存泄露是無害的,因為像這樣的小程序,在結(jié)束時操作系統(tǒng)將會釋放程序占用的內(nèi)存堆。下面我們來編譯這個程序。建立一個名為hello的目錄,在目錄下建立一個名為hello.cpp的c+源文件,將上面的代碼寫入文件中。運行“開始程序Qt by TrolltechQt Command Prompt”。在命令行模式下,切換目錄到hello下,然后輸入命令:qmake project。這個命令將產(chǎn)生一個依賴于工作平臺的工程文件()。再輸入命令:qmake 。這個命令通過工程文件產(chǎn)生一個可以在特定工作平臺上使用的makefile。最后輸入命令:make

13、來產(chǎn)生應(yīng)用程序。運行這個程序,可以得到如下的程序界面。 Qt也支持XML。我們可以把程序的第6行替換成下面的語句:QLabel *label = new QLabel (Hello Qt! );重新編譯程序,我們發(fā)現(xiàn)界面擁有了簡單的HTML風(fēng)格。如下圖: 2、調(diào)用退出第二個例子展示了如何使應(yīng)用程序?qū)τ脩舻膭幼鬟M(jìn)行響應(yīng)。這個應(yīng)用程序包括了一個按鈕,用戶可以點擊這個按鈕來退出程序。程序代碼與上一個程序非常相似,不同之處在于我們使用了一個QPushButton來代替QLabel作為我們的主窗口,并且我們將一個用戶動作(點擊一個按鈕)和一些程序代碼連接起來。 1 #include 2 #include

14、 3 int main (int argc, char *argv ) 4 5 QApplication app (argc, argv); 6 QPushButton *button = new QPushButton (Quit); 7 QObject:connect (button, SIGNAL (clicked (), 8 &app, SLOT (quit (); 9 button-show ();10 return app. exec ();11 Qt程序的窗口部件發(fā)射信號(signals)來指出一個用戶的動作或者是狀態(tài)的變化。在這個例子中,當(dāng)用戶點擊這個按鈕的時候,QPushBu

15、tton就會發(fā)射一個信號clicked()。一個信號可以和一個函數(shù)(在這種情況下我們把這個函數(shù)叫做“槽(slot)”)相連,當(dāng)信號被發(fā)射的時候,和信號相連的槽就會自動執(zhí)行。在這個例子中,我們把按鈕的信號“clicked()”和一個QApplication對象的槽“quit()”相連。當(dāng)按鈕被按下的時候,這個程序就退出了。3、窗口布局在本小節(jié),我們將用一個樣例來展現(xiàn)如何在窗口中規(guī)劃各個部件的布局,并學(xué)習(xí)使用信號和槽來使兩個窗口部件同步。這個應(yīng)用程序要求輸入用戶的年齡,使用者可以通過一個旋轉(zhuǎn)窗口或者一個滑塊窗口來輸入。 這個應(yīng)用程序包括三個窗口部件:一個QSpinBox,一個QSlider和一個Q

16、Widget。窗口部件QWidget是程序的主窗口。QSpinBox和QSlider被放置在QWidget中;他們是QWidget的子窗口。當(dāng)然,我們也可以說QWidget是QSpinBox和QSlider的父窗口。QWidget本身沒有父窗口,因為它被當(dāng)作一個頂級的窗口。QWidget以及所有它的子類的構(gòu)造函數(shù)都擁有一個參數(shù):QWidget *,這說明了它的父窗口。下面是程序的代碼:1 #include 2 #include 3 #include 4 #include 5 int main (int argc, char *argv ) 6 7 QApplication app (argc,

17、 argv); 8 QWidget *window = new QWidget; 9 window-setWindowTitle (Enter Your Age);10 QSpinBox *spinBox = new QSpinBox;11 QSlider *slider = new QSlider (Qt:Horizontal);12 spinBox-setRange (0, 130);13 slider-setRange (0, 130);14 QObject:connect (spinBox, SIGNAL (valueChanged (int),15 slider, SLOT (set

18、Value (int);16 QObject:connect (slider, SIGNAL (valueChanged (int),17 spinBox, SLOT (setValue (int);18 spinBox-setValue (50);19 QHBoxLayout *layout = new QHBoxLayout;20 layout-addWidget (spinBox);21 layout-addWidget (slider);22 window-setLayout (layout);23 window-show ();24 return app. exec ();25 第8

19、行和第9行設(shè)置了QWidget,它將被作為程序的主窗口。我們調(diào)用函數(shù)setWindowTitle()來設(shè)置窗口的標(biāo)題欄。第10行和第11行創(chuàng)建了一個QSpinBox和一個QSlider,第12行和第13行設(shè)置了它們的取值范圍(我們假設(shè)用戶最大也只有130歲)。我們可以將之前創(chuàng)建的QWidget對象window傳遞給QSpinBox和QSlider的構(gòu)造函數(shù),用來說明這兩個對象的父窗口,但是這么做并不是必須的。原因是窗口布局系統(tǒng)將會自己指出這一點,自動將window設(shè)置為父窗口。我們一會兒就可以看到這個特性。在第14行和第17行,兩個對于QObject:connect()函數(shù)的調(diào)用確保了旋轉(zhuǎn)窗口

20、和滑塊窗口的同步,這樣這兩個窗口總是顯示同樣的數(shù)值。不管一個窗口對象的數(shù)值何時發(fā)生變化,它的信號valueChanged(int)就將被發(fā)射,而另一個窗口對象的槽setValue(int)會接受到這個信號,使得自身的數(shù)值與其相等。第18行將旋轉(zhuǎn)窗口的數(shù)值設(shè)置為50。當(dāng)這個事件發(fā)生的時候,QSpinBox發(fā)射信號valueChanged(int),這個信號包括一個值為50的整型參數(shù)。這個參數(shù)被QSlider的槽setValue(int)接受,就會將滑塊的值也設(shè)置為50。由于QSlider的值被改變,所以QSlider也會發(fā)出一個valueChanged(int)信號并觸發(fā)QSpinBox的set

21、Value(int)槽。但是在這個時候,QSpinBox不會再發(fā)出任何信號,因為旋轉(zhuǎn)窗口的值已經(jīng)被設(shè)置為50了。這將有效地防止信號的無限循環(huán)。從第19行到第22行,我們通過使用一個layout管理器對旋轉(zhuǎn)窗口和滑塊窗口進(jìn)行了布局設(shè)置。一個布局管理者就是一個根據(jù)窗口作用設(shè)置其大小和位置的對象。Qt有三個主要的布局管理類:QHBoxLayout:將窗口部件水平自左至右設(shè)置(有些情況下是自右向左)。QVBoxLayout:將窗口部件垂直自上向下設(shè)置。QGridLayout: 以網(wǎng)格形式設(shè)置窗口部件。第22行我們調(diào)用QWidget:setLayout()函數(shù)在對象window上安裝布局管理器。通過這個

22、調(diào)用,QSpinBox和QSlider自動成為布局管理器所在窗口的子窗口。現(xiàn)在我們明白為什么在設(shè)置子窗口時不用顯式地說明父窗口了。可以看到,雖然沒有明顯地給出任何窗口的大小和位置,但QSpinBox和QSlider是很完美地被水平依次放置的。這是因為QHBox-Layout根據(jù)各個窗口的作用自動的為其設(shè)置了合理的大小和位置。這個功能使我們從煩瑣的界面調(diào)整中解放出來,更加專注于功能的實現(xiàn)。Qt構(gòu)建用戶界面的方法很容易理解,并且有很高的靈活性。Qt程序員最常用的設(shè)計模式是:說明所需要的窗口部件,然后設(shè)置這些部件必須的特性。程序員把窗口部件添加到布局管理器中,布局管理器就將自動地設(shè)置這些部件的大小和

23、位置。而用戶界面的行為是通過連接各個部件(運用信號/槽機(jī)制)來實現(xiàn)的。4、派生QDialog我們現(xiàn)在開始嘗試著在Qt里只用C+語言而不是借助界面設(shè)計器來完成一個對話框:FIND。我們將這個對話框作為一個類來完成,這么做的好處是我們使這個對話框成為了一個獨立的,擁有自己的信號和槽的,設(shè)備齊全的組件。 程序的源代碼由兩部分組成:finddialog.h和finddialog.cpp。我們從頭文件開始。1 #ifndef FINDDIALOG_H2 #define FINDDIALOG_H3 #include 4 class QCheckBox;5 class QLabel;6 class QLin

24、eEdit;7 class QPushButton;第1行,第2行(和第27行)的作用是防止頭文件被重復(fù)包含。第3行包含了QDialog的定義。QDialog從QWidget繼承而來,是Qt的對話框基類。第4行到第7行是對我們將要用來填充對話框的對象的類的預(yù)定義。一個預(yù)先的聲明將會告訴C+編譯器這個類的存在,而不用給出所有關(guān)于實現(xiàn)的細(xì)節(jié)。然后我們定義FindDialog作為QDialog的一個子類:8 class FindDialog: public QDialog9 10 Q_OBJECT11 public:12 FindDialog (QWidget *parent = 0);在類定義頂端

25、出現(xiàn)了宏:Q_OBJECT。這對于所有定義了信號或槽的類都是必須的。FindDialog的構(gòu)造函數(shù)擁有Qt窗口類的典型特征。參數(shù)parent聲明了父窗口。其默認(rèn)值是一個空指針,表示這個對話框沒有父窗口。13 signals:14 void findNext (const QString &str, Qt:CaseSensitivity cs);15 void findPrevious (const QString &str, Qt:CaseSensitivity cs);標(biāo)記為 signals的這一段聲明了兩個信號。當(dāng)用戶點擊對話框的“Find”按鈕的時候,信號將被發(fā)射。如果選項“Search

26、 backward”被選中,對話框?qū)l(fā)射消息findPrevious();相反的,對話框?qū)l(fā)射消息findNext()。關(guān)鍵字“signals”實際上也是一個宏。C+預(yù)處理器將在編譯器看到它之前就已經(jīng)將它轉(zhuǎn)換為了標(biāo)準(zhǔn)的C+。Qt:CaseSecsitivity是一個枚舉類型。它可以代表值Qt:CaseSensitive和Qt:CaseInsensitive。16 private slots:17 void findClicked ();18 void enableFindButton (const QString &text);19 private:20 QLabel *label;21 QL

27、ineEdit *lineEdit;22 QCheckBox *caseCheckBox;23 QCheckBox *backwardCheckBox;24 QPushButton *findButton;25 QPushButton *closeButton;26 ;27 #endif在類的private字段中,我們聲明了兩個槽。為了實現(xiàn)這些槽,我們需要訪問大多數(shù)對話框的子窗口,所以我們在私有字段中保留了這些子窗口的指針。和signals一樣,關(guān)鍵字slots也是一個構(gòu)造后可以被C+編譯器辯識的宏。對于私有變量,我們使用了它們的類的預(yù)定義。這是被編譯器所允許的,因為他們都是指針,而我們在頭文

28、件中并不需要訪問他們,所以編譯器并不需要完整的類定義。我們可以在頭文件中包含使用這些類所需要的頭文件(,,等等),但是使用預(yù)定義可以在某種程度上加快編譯過程。現(xiàn)在我們來看源文件finddialog.cpp。源文件里包括了FindDialog類的實現(xiàn)。1 #include 2 #include finddialog.h首先,我們包含了。這個頭文件包含了對于Qt的GUI類的定義。Qt包括一些模塊,每一個模塊都依賴于自己的庫文件。最重要的幾個模塊分別是QtCore, QtGui, QtNetwork, QtOpenGL, QtSpl, QtSvg和QtXml。頭文件包括了QtCore和QtGui模塊

29、中所有類的實現(xiàn)。包含此頭文件使我們不用單獨地列出每個類所需要的頭文件。在filedialog.h中,我們也可以簡單地包含,而不是像我們之前做的那樣包括,并且給QCheckBox,QLabel,QLineEdit,QPushButton提供預(yù)定義。這樣似乎簡單一些,但是在頭文件中包含另外一個大的頭文件是一個很壞的方式,尤其是在比較大的應(yīng)用當(dāng)中。3 FindDialog:FindDialog (QWidget *parent) 4 : QDialog (parent) 5 6 label = new QLabel (tr (Find &what :); 7 lineEdit = new QLine

30、Edit; 8 label-setBuddy (lineEdit); 9 caseCheckBox = new QCheckBox (tr (Match &case);10 backwardCheckBox = new QCheckBox (tr (Search &backward);11 findButton = new QPushButton (tr (&Find);12 findButton-setDefault (true);13 findButton-setEnabled (false);14 closeButton = new QPushButton (tr (Close);在第4

31、行,我們將參數(shù)parent傳遞給基類的構(gòu)造函數(shù)。然后我們創(chuàng)建子窗口。對于所有的字符串我們都調(diào)用函數(shù)tr(),這些字符串被標(biāo)記為可以翻譯成別的語言。函數(shù)tr()在QObject和每個含有Q_OBJECT宏的子類中被定義。將沒一個用戶可見的字符串都用TR()包括起來是一個很好的習(xí)慣,即使你現(xiàn)在并沒有將程序翻譯為別的語言的計劃。對于Qt應(yīng)用程序的翻譯將在后述章節(jié)中詳細(xì)呈現(xiàn)。在字符串中,我們用操作符&來指出快捷鍵。例如,第11行創(chuàng)建了一個”Find”按鈕。在支持快捷鍵的平臺上用戶可以按下Alt+F來切換到這個按鈕上。操作符&也可以用來控制程序焦點:在第6行我們創(chuàng)建了一個擁有快捷鍵(Alt+W)的標(biāo)簽,

32、在第8行我們給這個標(biāo)簽設(shè)置一個伙伴(buddy):lineEdit。一個buddy就是當(dāng)標(biāo)簽的快捷鍵被按下的時候,接收程序焦點的窗口。所以,當(dāng)用戶按下Alt+W的時候,程序焦點轉(zhuǎn)移到字符編輯框上。在第12行,通過調(diào)用函數(shù)setDefault(true),我們將按鈕Find設(shè)置為程序的默認(rèn)按鈕(所謂的默認(rèn)按鈕就是當(dāng)用戶按下回車鍵時被觸發(fā)的按鈕)。在第13行,我們將按鈕Find設(shè)置為不可用。當(dāng)一個窗口被設(shè)置為不可用的時候,它通常顯示為灰色,并不會和用戶產(chǎn)生任何交互。15 connect (lineEdit, SIGNAL (textChanged (const QString &),16 this

33、, SLOT (enableFindButton (const QString &);17 connect (findButton, SIGNAL (clicked (),18 this, SLOT (findClicked ();19 connect (closeButton, SIGNAL (clicked (),20 this, SLOT (close ();當(dāng)字符編輯框中的文字被改變的時候,私有的槽enableFindButton(const QString &)被調(diào)用。私有槽findClicked()在用戶點擊Find按鈕時被調(diào)用。當(dāng)用戶點擊關(guān)閉的時候,對話框?qū)㈥P(guān)閉自身。槽close

34、()是從QWidget繼承而來的,它的默認(rèn)行為是隱藏窗口對象(而不是刪除它)。我們馬上就能看到槽enableFindButton()和findClicked()的代碼。由于QObject是FindDialog的一個父類,所以我們可以在調(diào)用connect()函數(shù)時忽略前面的前綴QObject: 。21 QHBoxLayout *topLeftLayout = new QHBoxLayout;22 topLeftLayout-addWidget (label);23 topLeftLayout-addWidget (lineEdit);24 QVBoxLayout *leftLayout = ne

35、w QVBoxLayout;25 leftLayout-addLayout (topLeftLayout);26 leftLayout-addWidget (caseCheckBox);27 leftLayout-addWidget (backwardCheckBox);28 QVBoxLayout *rightLayout = new QVBoxLayout;29 rightLayout-addWidget (findButton);30 rightLayout-addWidget (closeButton);31 rightLayout-addStretch ();32 QHBoxLayo

36、ut *mainLayout = new QHBoxLayout;33 mainLayout-addLayout (leftLayout);34 mainLayout-addLayout (rightLayout);35 setLayout (mainLayout);接下來,我們使用布局管理器來對子窗口部件進(jìn)行布局。布局管理器可以包括窗口,也可以包括其它的布局管理器。通過對QHBoxLayout,QVBoxLayout和QGridLayout這三個布局管理類的嵌套使用,就可以生成非常復(fù)雜的對話框了。如上圖所示,對于對話框Find,我們使用了兩個QHBoxLayout和兩個QVBoxLayout

37、。最外層的布局是主要的布局,它在第35行被安裝并負(fù)責(zé)響應(yīng)對話框的全部區(qū)域。另外的三個布局是子布局。圖的右下方有一個“彈簧”,這是個空白的區(qū)域。在按鈕Find和Close的下方使用空白是為了保證這些按鈕出現(xiàn)在它們所在的布局的上方。一個比較微妙的地方是布局管理類并不是窗口對象。它們從QLayout繼承而來,而QLayout從QObject繼承而來。在上圖中,窗口以實線標(biāo)記,而布局以虛線標(biāo)記。在一個正在運行的程序當(dāng)中,布局是不可見的。當(dāng)子布局被添加到父布局中的時候(代碼的第25行,33行和34行),子布局自動子類化。當(dāng)主布局被安裝的時候(第35行),它成為了對話框的一個子類,所以在布局當(dāng)中的所有窗口

38、對象都成為了對話框的子類。本例中各個類的繼承層次在下圖中表明。36 setWindowTitle (tr (Find);37 setFixedHeight (sizeHint ().height ();38 在代碼的最后,我們將對話框標(biāo)題欄的內(nèi)容設(shè)置為“Find”,然后給窗口設(shè)置一個合適的高度。由于這個對話框中沒有任何子窗口可能占據(jù)多余的垂直空間,函數(shù)QWidget:sizeHint()將會返回一個“理想”的大小。考慮一下FindDialog的構(gòu)造過程。由于我們使用了new來生成對話框的窗口和布局,看起來我們應(yīng)該為每一個窗口和布局編寫一個析構(gòu)函數(shù)來調(diào)用delete。事實上這不是必須的,因為在父

39、窗口被銷毀的時候,Qt將會自動刪除所有的子對象。本例中,所有的窗口和布局都是從FindDialog繼承而來,在對話框被關(guān)閉的時候,這些子對象也會被自動銷毀。現(xiàn)在我們看一下對話框的槽:39 void FindDialog:findClicked ()40 41 QString text = lineEdit-text ();42 Qt:CaseSensitivity cs =43 caseCheckBox-isChecked ()? Qt:CaseSensitive44 : Qt:CaseInsensitive;45 if (backwardCheckBox-isChecked () 46 em

40、it findPrevious (text, cs);47 else 48 emit findNext (text, cs);49 50 51 void FindDialog:enableFindButton (const QString &text) 52 findButton-setEnabled (! text.isEmpty ();53 當(dāng)用戶按下Find按鈕時,按鈕會發(fā)射findPrevious()或者findNext()信號,槽findClicked()會被調(diào)用。關(guān)鍵字emit在Qt里很特殊,和其它的Qt擴(kuò)展名一樣,它在被傳遞給標(biāo)準(zhǔn)C+編譯器之前會被C+預(yù)處理器轉(zhuǎn)換。當(dāng)用戶改變字符

41、編輯框中的內(nèi)容時,槽enableFindButton()被調(diào)用。也就是說,當(dāng)字符編輯框中有內(nèi)容時,F(xiàn)ind按鈕是可見的;當(dāng)編輯框中沒有內(nèi)容的時候,F(xiàn)ind按鈕不可見。這兩個槽被定義之后,我們關(guān)于這個對話框的內(nèi)容就完成了。現(xiàn)在可以創(chuàng)建一個名為main.cpp的文件來試驗一下FindDialog窗口。1 #include 2 #include finddialog.h3 int main (int argc, char *argv )4 5 QApplication app (argc, argv);6 FindDialog *dialog = new FindDialog;7 dialog-sh

42、ow ();8 return app. exec ();9 現(xiàn)在可以編譯并運行這個程序了。如果你的平臺支持快捷鍵,嘗試著使用快捷鍵Alt+W,Alt+C,Alt+B和Alt+F來觸發(fā)正確的行為。按下Tab鍵來切換各個窗口。默認(rèn)的tab順序在程序生成時已經(jīng)確定。如果想更改這個順序,可以調(diào)用函數(shù)QWidget:setTabOrder()。以上我們派生了QDialog來生成對話框。同樣的道理,我們也通過可以派生QMainWindow來生成程序主窗口,然后在主窗口中創(chuàng)建菜單和工具條。也就是說,我們可以通過只編寫代碼來生成一個完整的程序。5、關(guān)于“信號和槽”(signal and slot)通過上幾節(jié)我

43、們已經(jīng)看到了“信號與槽”的運用。下面我們詳細(xì)解釋這個機(jī)制以及一些相關(guān)的內(nèi)容。使用信號與槽的基本格式為:connect (sender, SIGNAL (signal), receiver, SLOT (slot);這里的sender和receiver是指向QObject的指針,而signal和slot是無參數(shù)名的函數(shù)信號。“信號和槽”機(jī)制用于Qt對象間的通訊。“信號/槽”機(jī)制是一種關(guān)于無縫對象通訊的機(jī)制,它是Qt的一個中心特征,也是Qt與其它工具包的最不相同的部分。在圖形用戶界面編程中,我們經(jīng)常希望一個窗口部件的一個變化被通知給另一個窗口部件。更一般地,我們希望任何一類的對象可以和其它對象進(jìn)行

44、通訊。例如,如果我們正在解析一個XML文件,當(dāng)我們遇到一個新的標(biāo)簽時,我們也許希望通知列表視圖我們正在用來表達(dá)XML文件的結(jié)構(gòu)。較老的工具包使用一種被稱作回調(diào)(callback)的通訊方式來實現(xiàn)同一目的。回調(diào)是指一個函數(shù)的指針,如果你希望一個處理函數(shù)通知你一些事件,你可以把另一個函數(shù)(回調(diào))的指針傳遞給處理函數(shù)。處理函數(shù)在適當(dāng)?shù)臅r候調(diào)用回調(diào)。回調(diào)有兩個主要缺點:首先他們不是類型安全的。我們從來都不能確定處理函數(shù)使用了正確的參數(shù)來調(diào)用回調(diào)。其次回調(diào)和處理函數(shù)是非常強有力地聯(lián)系在一起的,因為處理函數(shù)必須知道要調(diào)用哪個回調(diào)。 在Qt中我們有一種可以替代回調(diào)的技術(shù)。我們使用信號和槽。當(dāng)一個特定事件發(fā)生

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

46、來,槽會在正確的時間使用信號的參數(shù)而被調(diào)用。信號和槽可以使用任何數(shù)量、任何類型的參數(shù)。它們是完全類型安全的:不會再有回調(diào)核心轉(zhuǎn)儲(core dump)。從QObject類,或者它的一個子類(比如QWidget類)所繼承出的所有類,都可以包含信號和槽。當(dāng)對象改變它們的狀態(tài)的時候,信號被發(fā)送,這就是所有的對象通訊時所做的一切。它不執(zhí)導(dǎo)也不注意有沒有對象接收它所發(fā)射的信號。槽用來接收信號,但它們同時也是對象中正常的成員函數(shù)。一個槽不知道它是否被任意信號連接。此外,對象并不知道關(guān)于這種通訊的機(jī)制。你可以把很多信號和你所希望的單一槽相連,并且一個信號也可以和你所期望的許多槽相連。把一個信號和另外一個信號

47、直接相連也是可行的(這種情況下,只要第一個信號被發(fā)射,第二個信號就會被立即發(fā)射)。 一個小例子一個最小的C+類聲明如下: class Foo public: Foo (); int value () const return val ; void setValue (int); private: int val; ;一個小的Qt類聲明如下:Class Foo: public QObjectQ_OBJECTPublic:Foo (); int value () const return val ;public slots:void setValue(int);signals:void value

48、Changed (int); private:int val;這個類有同樣的內(nèi)部狀態(tài),和公有方法訪問狀態(tài),但是另外它也支持使用信號和槽的組件編程:這個類可以通過發(fā)射一個信號:valueChanged()來告訴外界它的狀態(tài)發(fā)生了變化,并且它有一個槽,其它對象可以發(fā)送信號給這個槽。所有包含信號和/或者槽的類必須在它們的聲明中提到Q_OBJECT。槽可以由應(yīng)用程序的編寫者來實現(xiàn)。這里是Foo:setValue()一個可能的實現(xiàn):Void Foo:setValue (int v)if (v != val) val = v;emit valueChanged (v);emit valueChanged(

49、v)這一行從對象中發(fā)射valueChanged信號。正如你所能看到的,你通過使用emit signal(arguments)來發(fā)射信號。下面是把兩個對象連接在一起的一種方法: Foo a, b; connect (&a, SIGNAL (valueChanged (int), &b, SLOT (setValue (int); b.setValue (11); / a = undefined b = 11 a.setValue (79); / a = 79 b = 79b.value (); 調(diào)用a.setValue(79)會使a發(fā)射一個valueChanged() 信號,b將會在它的setV

50、alue()槽中接收這個信號,也就是b.setValue(79) 被調(diào)用。接下來b會發(fā)射同樣的valueChanged()信號,但是因為沒有槽被連接到b的valueChanged()信號,所以沒有發(fā)生任何事(信號消失了)。 注意:只有當(dāng)v != val的時候setValue()函數(shù)才會設(shè)置這個值并且發(fā)射信號。這樣就避免了在循環(huán)連接的情況下(比如b.valueChanged() 和a.setValue()連接在一起)出現(xiàn)無休止的循環(huán)的情況。 這個例子說明了對象之間可以在互相不知道的情況下一起工作,只要在最初的時在它們中間建立連接。預(yù)處理程序改變或者移除了signals、slots和emit 這些

51、關(guān)鍵字,這樣就可以使用標(biāo)準(zhǔn)的C+編譯器。在一個定義有信號和槽的類上運行moc。這樣就會生成一個可以和其它對象文件編譯和連接成引用程序的C+源文件。 信號當(dāng)對象的內(nèi)部狀態(tài)發(fā)生改變,信號就被發(fā)射,只有定義了一個信號的類和它的子類才能發(fā)射這個信號。例如,一個列表框同時發(fā)射highlighted()和activated()這兩個信號。絕大多數(shù)對象也許只對activated()這個信號感興趣,但是有時我們也想知道列表框中的哪個條目在當(dāng)前是高亮的。如果兩個不同的類對同一個信號感興趣,你可以把這個信號和這兩個對象連接起來。 當(dāng)一個信號被發(fā)射,它所連接的槽會被立即執(zhí)行,就像一個普通函數(shù)調(diào)用一樣。信號/槽機(jī)制完

52、全不依賴于任何一種圖形用戶界面的事件回路。當(dāng)所有的槽都返回后 emit也將返回。 如果幾個槽被連接到一個信號,當(dāng)信號被發(fā)射時,這些槽就會被按任意順序一個接一個地執(zhí)行。 信號會由moc自動生成并且一定不要在.cpp文件中實現(xiàn)。它們也不能有任何返回類型(比如使用void)。 關(guān)于參數(shù)需要注意。我們的經(jīng)驗顯示如果信號和槽不使用特殊的類型,它們都可以多次使用。如果QScrollBar:valueChanged() 使用了一個特殊的類型,比如hypothetical QRangeControl:Range,它就只能被連接到被設(shè)計成可以處理 QRangeControl的槽。 槽當(dāng)一個和槽連接的信號被發(fā)射的

53、時候,這個操被調(diào)用。槽也是普通的C+函數(shù)并且可以像它們一樣被調(diào)用;它們唯一的特點就是它們可以被信號連接。槽的參數(shù)不能含有默認(rèn)值,并且和信號一樣,為了槽的參數(shù)而使用自己特定的類型是很不明智的。因為槽就是普通成員函數(shù),但卻有一點非常有意思的東西,它們也和普通成員函數(shù)一樣有訪問權(quán)限。一個槽的訪問權(quán)限決定了誰可以和它相連:一個public slots:區(qū)包含了任何信號都可以相連的槽。這對于組件編程來說非常有用:你生成了許多對象,它們互相并不知道,把它們的信號和槽連接起來,這樣信息就可以正確地傳遞,并且就像一個鐵路模型,把它打開然后讓它跑起來。一個protected slots:區(qū)包含了之后這個類和它的子類的信號才能連接的槽。這就是說這些槽只是類的實現(xiàn)的一部分,而不是它和外界的接口。 一個private slots:區(qū)包含了之后這個類本身的信號可以連接的槽。這就是說它和這個類是非常緊密的,甚至它的子類都沒有獲得連接權(quán)利這樣的信任。你也可以把槽定義為虛的,這在實踐中被發(fā)現(xiàn)也是非常有用的。6、關(guān)于元對象系統(tǒng)(Meta-Object System)Qt的一個最主要的特點可能就是它擴(kuò)展了C+的機(jī)制,可以創(chuàng)建獨立的軟件組件,這些組件可以被綁定在一起,而不需要互相的任何了解。這個機(jī)制被成為元對象系統(tǒng),它提供了兩個關(guān)鍵服務(wù):信號/槽、運行時的類型信息和動態(tài)屬性系統(tǒng)(內(nèi)省

溫馨提示

  • 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論