天天看點

widget,MainWindow和Dialog的選擇使用

Qt中的每個類,都有一個對應的同名頭檔案,其中包含其類定義。例如要使用QApplication類,則需要在程式中添加" #include <QApplication>" 

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層次的特别設定

繼續閱讀