widget,MainWindow和Dialog的選擇使用
QApplication類用於管理應用程式範圍內的資源。其建構函式需要main函式的argc和argv作為引數。
widget被建立時都是不可見的(always created hidden)。widget中可容納其它widget。
Qt中的widget在有使用者行為或狀態改變時會emit signal。 signal可以和slot函式連線在一起(connect),這樣當有signal被emit時,對應的slot函式會被自動呼叫。
QWidget類的建構函式需要一個 QWidget * 指標作為引數,表示其parent widget(預設值為0,即不存在parent widget)。在parent widget被刪除時,Qt會自動刪除其所有的child widget。
Qt中有三種Layout Manager 類: QHBoxLayout,QVBoxLayOut,QGridLayOut。基本模式是將widget新增進LayOut,由Layout自動接管widget的尺寸和位置。
啟動Qt程式時可以通過 -style 引數改變程式的預設顯式風格。
Chapter 2 Creating Dialogs
2.1 Subclassing Dialog
Qt中所有dialog的基類是QDialog。QDialog派生自QWidget。
Qt中所有定義了signal或slot的類,在其類定義的開始處都要使用Q_OBJECT巨集。Qt中的signal關鍵字實際上是巨集定義。類似的,slots關鍵字也是巨集定義。
Qt所提供的類分為若干模組:QtGui,QtNetWork,QtOpenGL,QtSql, QtSvg和QtXml等。
QObject::tr() 函式將輸入的字串轉換為其他語言(國際化)。對所有使用者可見的字串都使用tr()函式是一個良好的習慣。
Buddy:兩個widget A和B,若A擁有快捷鍵,當用戶按下該快捷鍵時,程式的輸入焦點自動轉移到B上,則稱B是A的buddy。
QWidget::close() 是一個slot,其預設行為是使對應的widget隱藏不可見,但並不刪除該widget。
Layout 中可包含widget和其他layout。通過巢狀使用QHBoxLayOut、QVBoxLayOut、QGridLayOut,可以構造非常複雜的dialog。值得注意的是:layout manager 類並不屬於widget。實際上,它派生自QLayout,而QLayout又派生自QObject。
QWidget::sizeHint() 返回一個widget()的理想大小(ideal size)。
emit關鍵字是Qt特有的,用於產生signal。
MOC(Meta-Object-Compiler): 對於所有使用了Q_OBJECT巨集的類,在編譯時都需要通過MOC的處理,否則會出現連結錯誤。解決該錯誤的辦法也很簡單,重新執行qmake以更新makefile,然後重新編譯。
2.2 Signal and Slot in Depth
Signal & Slot 機制是Qt的根基。
Slot和普通的C++類成員函式幾乎完全一致;可以是virtual的,可以被過載,可以是public、protected或private的,而且也可所以被其他成員函式直接呼叫。
signal與slot之間的關聯可以是一對一、一對多或多對一。
signal和signal之間也可以被關聯,此種情況與signal-slot的區別在於,當第一個sigal被emit時,第二個signal也被emit。
可以呼叫disconnect()來解除signal 與slot之間的關聯,通常情況下很少需要顯式呼叫disconnect(),因為物件被刪除時Qt會自動移除與其相關的關聯。
sigal-slot或signal-signal這樣的關聯,要求二者具備相同的引數列表;若signal比slot中的引數多,多餘的引數會被忽略。
思維定勢:signal-slot機制只能用於widget。實際上signal-slot機制是由QObject實現的,並不僅侷限於GUI程式設計,可以用於任何QObject子類。
2.3 Rapid Dialog Design
使用Qt Designer建立的form最終被轉換為C++程式碼。
qmake工具能夠檢測到interface file(*.ui files),並呼叫uic,即Qt的user interface compiler。uic將.ui檔案轉換為C++程式碼,並存放在形式為ui_xxx.h的檔案中。該檔案中給出了dialog對應類的完整定義,幷包含一個 setupUi()成員函式,用於初始化form。
注意,由uic建立的這個類未派生自任何Qt class。
Qt的 parent-child機制是由QObject實現的。當建立一個物件時若指定了parent,則parent將該物件新增至其 childern list。當parent被刪除時,Qt會遍歷其childern list並刪除每個child,該過程會遞迴進行。這一機制極大的簡化了記憶體管理,降低了記憶體洩露的風險——程式設計師只需顯式的刪除通過new建立並且沒有parent的物件。
對於widget,parent還有一層附加的意義:chidl widget 是顯示在parent widget的範圍之內的。如果刪除parent widget,不僅child widget從記憶體中被釋放,在螢幕上也會消失。
QDialog::accept() 將dialog的返回值設為QDialog::Accepted(值為1),而QDialog::reject()將返回值設為QDIalog::Rejected(值為0)。
2.5 Dynamic Dialogs
Dynamic Dialog指的是程式在執行時根據.ui檔案建立的dialog。這樣的dialog不是通過uic將.ui轉換為C++程式碼,而是在執行時使用QUiLoader類裝載.ui檔案。
可以使用QObject::findChild<T> ()來訪問form的child widget。
要使用QUiLoader,需要在Qt程式的.pro檔案中新增以下內容: CONFIG += uitools
Dynamic dialog允許在不重新編譯程式的前提下更改form的佈局。
Chapter 3 Creating Main Windows
3.1 Subclassing QMainWindow
應用程式的主視窗是通過建立QMainWindow的派生類來完成的。QMainWindow和QDialog一樣,都是派生自QWidget。
closeEvent()是由QWidget提供的一個虛擬函式,在使用者關閉視窗時會被自動呼叫。
setCentralWidget()將某個Widget設定為主視窗的central widget, 而central widget意味著在顯示時會佔據主視窗的中央位置。
Qt下的GUI 程式設計支援多種圖形格式。可以使用多種方式為應用程式提供影象,最常見的包括:
1). 將影象儲存在檔案中,執行時載入之。
2). 在原始碼中include XPM檔案(XPM檔案也是合法的C++檔案)。
3). 利用Qt的資源機制。
Qt的資源機制比之執行時載入更方便,並對所有支援的影象格式都能良好工作。
為了利用Qt的資源機制,需要建立一個資原始檔,並在.pro檔案中對應新增一行來對資原始檔進行標識。例如:
RESOURCES= spreadsheet.qrc
資原始檔本身採用了簡單的XML格式。它被編譯程序序的可執行檔案,因此不會被丟失。在對資源進行定位時,使用路徑字首":/",例如“ :/images/icon.png "。資源本身可以是任何型別的檔案。
3.2 Creating Menus and Toolbars
Qt通過引入Action這一概念簡化了對menu和toolbar的程式設計。一個Action可以被新增到任意數量menu和toobar中。
在Qt中對menu和toolbar的程式設計涉及到三個步驟:
1). 建立並設定Action
2). 建立menu,並在其中新增Action
3). 建立toolbar,並在其中新增Action
Action的建立是通過QAction類來實現的,對每個Action,可以為其設定accelerator,parent,shortcut key, 可見性以及status tip等屬性,並可以通過呼叫connect()為ACtion設定被觸發要執行的操作。
QTableWidget的基類QAbstraceItemView提供了selectAll()這個slot。
QApplication類提供了aboutQt()這個slot,可以通過全域性變數qApp(一個型別為QApplication *的指標)來使用之。
在Qt中,menu由QMenu類的例項表示。而Qmenu是要被放入QMenuBar之中的。函式QMainWindow::menuBar()返回一個型別為QMenuBar * 的指標。QMenuBar::addMenu()根據指定文字建立一個QMenu widget並將其新增進MenuBar中。QMenu::addAction() 則為Menu新增Action。
任意Qt Widget都可以具備相關的一系列QAction。通過呼叫QWidget::addAction() ,可以為Widget新增Action。這一特性可用來建立上下文選單。
3.3 Setting Up the Status Bar
QMainWindow::statusBar() 返回一個指向status bar的指標;status bar 在statusBar()第一次被呼叫時被建立。
3.4 Implementing The Menu
QMessageBox::Defalut修飾符使得被修飾的Button成為預設Button,而QMessage::Escape修飾符則使得Esc鍵自動觸發被修飾的Button。
QMessageBox::warning()用於彈出提示對話方塊。該函式屬於Qt提供的static convenicence function
static convenience function
QFileDialog::getOpenFileName() 可用於從使用者處獲得檔名——該函式彈出一個檔案選擇對話方塊,要求使用者選擇一個檔案,並返回檔名,或者在使用者選擇"Cancel"時返回空字串。該函式的第一個引數是其parent widget。對於dialog和其他widget,parent-child關係的意味是不完全相同的。一個dialog永遠是一個獨立的視窗,但是如果它擁有parent,則預設在parent之上居中顯示。
當用戶發出關閉視窗的操作時,Qwidget::close() 這個slot會被呼叫,該slot向對應的widget傳送close event。重新實現QWidget::closeEvent()能夠攔截這個event,以便確定是否真的要關閉視窗,防止誤操作。
每個QWidget都有一個windowModified屬性,在視窗文件被修改時應該被設為True,否則被設為false。
QString::arg() 函式將字串中編號最低的"%n"用引數進行替換,並返回替換後的字串。
每個Action都可以擁有一個型別為QVariant的關聯資料。
Qt中的qobject_cast<T>() 機制對於動態庫也可以正常工作。
3.5 Using Dialog
modeless window——one that runs independently of any other windows in the application
對於modeless dialog ,當其被彈出時,可能處於三種情況:
1). 這是該對話方塊第一次被啟用
2). 該對話方塊之前曾被啟用,但使用者又將其關閉
3). 該對話方塊之前曾被啟用,而且仍可見
show() 將一個隱藏視窗變為可見,而activateWIndow()則將視窗的狀態變為active。
model window——pops up when invoked and blocks the application,preventing any other processing or interactions until it is closed.
一個dialog若是用show()來啟用,則是modeless dialog;若通過exec()來啟用,則是model dialog。此外,還可以呼叫setModel()來設定dialog的顯示模式。
QDialog::exec() 的返回至在dialog被確認時為true,否則為false。
在棧上建立 model dialog是一種良好的程式設計慣例,因為在使用完後就不再需要,而model dialog會在作用域結束後自動被銷燬。
由於多數應用程式的About box 都是高度雷同的,Qt中提供了一個方便的static convenicence function QMessage::about(),該函式和QMessageBox::warning()很相似。
3.6 Storing Setting
Qt中是通過QSettings類來將應用程式的設定資訊儲存到平臺相關的位置——windows下存入登錄檔中,unix中存在文字檔案中。
QSettings的建構函式包含兩個引數,分別是organization's name 和 application's name ,Qt使用這兩個引數來對應用程式的設定資訊進行定位。
QSettings以key-value pair的形式儲存資訊。
3.7 Multiple Documents
要想實現多文件程式,首先必須要通過new在堆上建立主視窗,而不是在棧上建立主視窗。
QAplication::closeAllWindows() 這個slot完成的操作是關閉應用程式所有的視窗,除非其中某個視窗拒絕了close event。程式設計師不需要擔心未儲存的修改,因為這會由QWidget::closeEvent()負責處理。
通過在MainWindow的建構函式中呼叫setAttribute()函式來設定Qt::WA_DeleteOnClose屬性,可以要求Qt在視窗被關閉時將其自動銷燬
Qt在其可用所有平臺上都支援SDI和MDI程式的建立。
3.8 Splash Screnns
在Qt中為程式新增splash screen非常簡單,可通過QSplashScreen類來實現。
通常情況下,與splash screen相關的程式碼都放在main()中,出現在呼叫QApplication::exec()之前。
Chapter 4 Implementing Application Functionality
4.1 The Central Widget
QMainWindow的中央區域可以被任何型別的widget佔據。
4.2 Subclassing QTableWidget
QTableWidget會自動建立QTableWidgetItem來儲存使用者的輸入。
QTableWidgetItem類並不是widget,而是一個純粹的data class。
QTabeWidget::setItermProtype()可以設定在獲得使用者輸入的情況下自動建立哪種cllass。
4.3 Loading and Saving
QFile & QDataStream
QFile的解構函式負責將開啟的檔案關閉。
QDataStream類具有很強的通用性,可作用於QFile,QBuffer,QProcess,QTcpSocket,QUdpSocket。
Qt還提供了一個QTextStream類用於專門讀寫文字檔案。
4.6 Subclassing QTableWidgetItem
每個QTableWidgetIterm中可儲存若干資料,這是通過個QVariant來實現的。每一個QVariant物件都以某個role來儲存某一類資料,常用的role有Qt::EditRole和Qt::DiaplayRole。
QVarinant物件可以存放多種型別的變數值,並提供向其他型別轉型的函式介面。
使用預設建構函式建立的QVariant物件被視為invalid variant。
Chapter 5. Creating Custom Widgets
使用者自定義的控制元件可以通過繼承現有的Qt控制元件實現,也可以直接從QWidget繼承來實現
5.1 Customizing Qt Widgets
5.2 Subclassing QWidget
通過對QWidget進行派生,並重新編寫其部分event handler來進行繪圖和響應使用者操作,程式設計師可以實現對widget的外觀和行為的完全控制。
Qt的內建Widget如QLabel、QPushButton、QTabelWidget等,就是以這種方式實現的。
巨集Q_PROPERTY()用來為widget宣告和新增自定義屬性。
每個屬性的定義都對應一個數據型別(任何被QVarinat支援的型別都可以),一個read function以及可選的write function。
對於包含自定義屬性的類,Q_OBJECT和Q_PROPERTY()這兩個巨集都是必備的。
QImage類以一種硬體無關的方式儲存影象資訊。
Qt中提供了兩個型別用於儲存色彩資訊:QRgb和QColor。
QRgb其實是一個typedef,用於存放32-bit的畫素資訊。
QColor則是一個提供了許多介面函式的類,在Qt中廣泛的用於儲存色彩。
QWidget::update()函式用於對widget進行強制性的重繪。
QWidget::updateGeometry()用於告知包含該widget的layout:該widget的size hint已發生變化,layout會自動進行調整。
通過呼叫QWidget::update()和QWidget::repaint(),可以強制性的產生一個 paint event,兩者的卻別在於repaint()導致立即重繪,而update()只是將一個paint event放入event queue中。
如果對update()進行連續多次呼叫,Qt會將連續的paint event壓縮合併為一個paint event,以防止影象抖動。
每個widget都擁有一個palette,用於設定widget中在什麼情況下使用什麼色彩,如背景色、文字色等。
widget的palette由三個color group組成:active ,inactive ,disabled。
QWidget::palette()以QPalette的形式返回widget的palette,而clolor group則通過列舉型別QPalette::ColorGroup指定
5.3 Intergrating Custom Widgets with Qt Designer
要像在Qt Designer中使用自定義widget的話,必須要讓Qt Designer能夠了解到它們的存在。
有兩種機制:promotion approach &plugin approach
promotion approach 很容易也很省時,但缺點是自定義widget的自定義屬性在Qt Designer中是不可見和不可訪問的,而使用plugin approach時則不存在這些問題。
plugin approach要求建立一個Qt Designer 可以在執行時載入的plugin library,以用於建立widget的例項。由於Qt的MOC機制,Qt Designer可以動態獲取widget的property list。
要使用plugin approach ,首先要對QDesignCustomWidgetInterface進行派生,並重寫某些虛擬函式。
Q_INTERFACES()巨集用於告知Qt該類實現了哪個interface。
在實現plugin class的原始檔尾部,必須使用Q_EXPORT_PLUGIN2()巨集使得該plugin對Qt Designer可見、可用。該巨集第一個引數是plugin的名字,第二個引數是實現該plugin的class name。
5.4 Double Buffering
QWidget::style()返回用於繪製該widget時所使用的style。Qt中的style都是QStyle的派生類。同一應用程式中的 widget一般都使用相同的style,然而可以呼叫QWidget::setStyle()來進行widget層次的特別設定