第八章 Qt GUI之對話框使用
對話框可以是模態(modal)的或非模態(modeless)兩種。當我們在一個用戶界面程序里面對一個對話框(比如選擇文件對話框)的操作沒有結束前,界面的其他窗口無法操作,遇到的這個對話框就是模態對話框,而當我們在一個字處理軟件中利用查找和替換對話框時,可以在字處理軟件和查找替換對話框之間切換進行交互,這就是個非模態對話框。
先來看一下QDialog類的繼承關系,如下圖所示。
QDialog從QWidget繼承,然后它下面又被Qt的內置對話框類(QFileDialog選擇文件或目錄對話框、QFontDialog選擇字體對話框、QMessageBox消息提示對話框等)繼承。用戶要實現自己的對話框,需要繼承自QDialog類,并包含頭文件<QDialog>。
一、快速設計對話框
例子1:
實現一個Find(查找對話框),它的運行效果如下圖所示,這將實現一個擁有自主權的對話框。
程序清單如下:
finddialog.h
1 #ifndef FINDDIALOG_H 2 #define FINDDIALOG_H 3 4 #include <QDialog> 5 #include <QCheckBox> 6 #include <QLabel> 7 #include <QLineEdit> 8 #include <QPushButton> 9 10 class FindDialog : public QDialog11 {12 Q_OBJECT13 14 public:15 FindDialog(QWidget *parent = 0);16 ~FindDialog();17 18 signals:19 void findNext(const QString &str, Qt::CaseSensitivity cs);20 void findPRevious(const QString &str, Qt::CaseSensitivity cs);21 22 private slots:23 void findClicked();24 void enableFindButton(const QString &text);25 26 private:27 QLabel *label;28 QLineEdit *lineEdit;29 QCheckBox *caseCheckBox;30 QCheckBox *backwardCheckBox;31 QPushButton *findButton;32 QPushButton *closeButton;33 };34 35 #endif // FINDDIALOG_H
finddialog.cpp:
1 #include <QtGui> 2 #include "finddialog.h" 3 4 FindDialog::FindDialog(QWidget *parent) 5 : QDialog(parent) 6 { 7 label = new QLabel(tr("Find &what")); //tr()函數是把它們翻譯成其他語言的標志,“&”來表示快捷鍵(Alt+W) 8 lineEdit = new QLineEdit; 9 label->setBuddy(lineEdit);//設置行編輯器為標簽的伙伴,按下標簽的快捷鍵(Alt+W)時接收焦點,焦點會移動到行編輯器10 11 caseCheckBox = new QCheckBox(tr("Math &case"));12 backwardCheckBox = new QCheckBox(tr("Search &backward"));13 14 findButton = new QPushButton(tr("&Find"));15 findButton->setDefault(true);//設置“Find”按鈕為默認按鈕,默認按鈕就是當用戶Enter鍵時能夠按下對應的按鈕16 findButton->setEnabled(false);//禁用“Find”按鈕,它通常顯示為灰色,不能和用戶進行交互操作17 18 closeButton = new QPushButton(tr("Close"));19 20 connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &)));21 connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked()));22 connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));23 24 QHBoxLayout *topLeftLayout = new QHBoxLayout;25 topLeftLayout->addWidget(label);26 topLeftLayout->addWidget(lineEdit);27 28 QVBoxLayout *leftLayout = new QVBoxLayout;29 leftLayout->addLayout(topLeftLayout);30 leftLayout->addWidget(caseCheckBox);31 leftLayout->addWidget(backwardCheckBox);32 33 QVBoxLayout *rightLayout = new QVBoxLayout;34 rightLayout->addWidget(findButton);35 rightLayout->addWidget(closeButton);36 rightLayout->addStretch();37 38 QHBoxLayout *mainLayout = new QHBoxLayout;39 mainLayout->addLayout(leftLayout);40 mainLayout->addLayout(rightLayout);41 setLayout(mainLayout); //將mainLayout布局安裝在FindDialog42 43 setWindowTitle(tr("Find"));44 setFixedHeight(sizeHint().height());45 }46 47 void FindDialog::findClicked()48 {49 QString text = lineEdit->text();50 Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;51 if (backwardCheckBox->isChecked())52 {53 emit findPrevious(text, cs);54 }55 else56 {57 emit findNext(text, cs);58 }59 }60 61 void FindDialog::enableFindButton(const QString &text)62 {63 findButton->setEnabled(!text.isEmpty());64 }65 66 FindDialog::~FindDialog()67 {68 69 }
main.cpp
#include <Qapplication>#include "finddialog.h"int main(int argc, char *argv[]){ QApplication a(argc, argv); FindDialog *w = new FindDialog; w->show(); return a.exec();}
編譯運行就出現上圖效果了。
例子2:
使用Qt designer設置對話框,實現效果如下圖:
基本步驟:
1、創建并初始化子窗口部件;
2、把子窗口部件放在布局中;
3、設置Tab鍵順序;
4、建立信號-槽之間的連接;
5、實現對話框的自定義槽。
第一步是創建子窗口部件并且把它們放置到窗體中。創建一個標簽(Label)、一個行編輯器(Line Edit)、一個水平分隔符(Horizontal Spacer)、兩個按鈕(Push Button)。
使用Qt設計師的屬性編輯器設置每個窗口部件的屬性:
1、單擊文本標簽。確保此時objectName的屬性是“label”,將它的text屬性設置成“&Cell Location”。
2、單擊行編輯器。確保objectName屬性是“lineEdit”。
3、單擊第一個按鈕。將它的objectName屬性設置成“okButton”,將它的enabled屬性設置成“false”,將它的text屬性設置成“OK”,并且把它的default屬性設置成“true”。
4、單擊第二個按鈕。將它的objectName屬性設置成“cancelButton”,并且將它的text屬性設置成“Cancel”。
5、單擊這個窗體中空白的地方,選中窗體本身。將它的windowTitle屬性設置成“Go to Cell”。
6、單擊Edit->Edit Buddies進入一種允許設置窗口部件伙伴(buddy)的特殊模式。然后,單擊這個標簽并把紅色箭頭拖到行編輯器上,釋放鼠標按鍵。單擊Edit->Edit Widgets離開伙伴設置模式。
下一步是在窗體中擺放這些窗口部件,步驟如下:
1、單擊“Cell Location”標簽并且按下ctrl鍵是單擊與之相鄰的行編輯器,這樣就可以同時選擇了它們,然后選擇水平布局(Lay Out Horizontally)。
2、選中分隔符、OK按鈕和Cancel按鈕,然后選擇水平布局(Lay Out Horizontally)。
3、單擊窗體中的空白,取消對所有已選中項的選擇,然后單擊垂直布局(Lay Out Vertically)。
4、單擊Edit->Edit Tab Order。在每一個可以接受焦點的窗口部件上,都會出現一個帶藍色矩形的數字,如下圖所示。按照你所希望的接受焦點的順序單擊每一個窗口部件,然后單擊Edit->Edit Widgets離開Tab鍵順序設置模式。
接下來添加代碼:
main.cpp
1 #include <QApplication> 2 #include "mywidget.h" 3 4 int main(int argc, char *argv[]) 5 { 6 QApplication a(argc, argv); 7 MyDialog w; 8 w.show(); 9 10 return a.exec();11 }
mywidget.h
1 #ifndef MYWIDGET_H 2 #define MYWIDGET_H 3 4 #include <QDialog> 5 6 namespace Ui { 7 class MyDialog; 8 } 9 10 class MyDialog : public QDialog11 {12 Q_OBJECT13 14 public:15 explicit MyDialog(QDialog *parent = 0);16 ~MyDialog();17 18 private slots:19 void on_lineEdit_textChanged();20 21 private:22 Ui::MyDialog *ui;23 };24 25 #endif // MYWIDGET_H
mywidget.cpp
1 #include "mywidget.h" 2 #include "ui_mywidget.h" 3 4 MyDialog::MyDialog(QDialog *parent) : 5 QDialog(parent), 6 ui(new Ui::MyDialog) 7 { 8 ui->setupUi(this); 9 10 QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");//建立一個正則表達式11 ui->lineEdit->setValidator(new QRegExpValidator(regExp, this)); //檢驗器限制輸入的范圍,12 //Qt提供3個內置檢驗器類:QIntValidator、QDoubleValidator、QRegExpValidator13 14 connect(ui->okButton, SIGNAL(clicked()), this, SLOT(accept())); //accept()槽函數關閉對話框,將對話框返回的結果變量設置為QDialog::Accepted(其值為1)15 connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(reject()));//reject()槽函數關閉對話框,將對話框返回的結果變量設置為QDialog::Reject(其值為0)16 }17 18 void MyDialog::on_lineEdit_textChanged()19 {20 ui->okButton->setEnabled(ui->lineEdit->hasAcceptableInput());21 }22 23 MyDialog::~MyDialog()24 {25 delete ui;26 }
最后點擊編譯運行就ok了。
二、可擴展的對話框
這部分內容直接截取別人的,不想寫。
前面我們設計的對話框都是不能改變它的樣子的。但是有時需要對話框根據要求進行適當的改變。兩個最常用的需要改變的對話框是可擴展對話框和多頁對話框。這兩種類型的可以通過代碼編寫,也可以用Qt Designer設計。一個例子如下圖所示:
可擴展對話框通常外觀簡單,帶有一個可擴展按鈕來切換對話框的簡單外觀和可擴展外觀。這種對話框通常為了迎合普通用戶和高端用戶而設計的,如果沒有特別請求隱藏高級應用部分。在這個實驗中,我們使用 Qt Designer設計一個可擴展對話框。
對話框是一個表格程序的排序對話框,對用戶選擇的一些列按要求排列。對話框的簡單外觀允許用戶輸入一個簡單排序關鍵詞,擴展部分允許輸入兩個額外的排序關鍵詞。一個More按鈕使用戶在簡單外觀和擴展外觀進行切換。
我們使用 Qt Designer創建這個可擴展的對話框,在運行時刻隱藏高級功能,這個看起來很復雜的對話框用Qt Designer可以很容易實現。首先設計好第一個關鍵詞,第二個和第三個關鍵詞通過復制就可以得到:
1、 啟動“文件”?“新建”菜單,選擇“Dialog without Buttons”模板。
2、 拖動一個PushButton按鈕并把它拖放到窗體的右上角。將它的objectName修改為“okButton”,并將它的default屬性設置為“true”,將它的text屬性設置為“確定”,這就創建了OK按鈕。
3、 同樣的辦法創建Cancel按鈕,放到OK按鈕的下方,將objectName修改為“cancelButton”,將text屬性設置為“取消”。
4、 創建一個垂直分隔符(Vertical Spacer)并將它放到Cancel按鈕的下方,然后再創建一個More按鈕,并將它放在垂直分隔符的下方,將More按鈕的objectName修改為“moreButton”,text屬性設置為“(&M)更多”,checkable屬性設置為“true”。
5、 選擇OK按鈕,Cancel按鈕,垂直分隔符和More按鈕,將它們的布局設定為“垂直布局”。
6、 創建一個群組框(GroupBox),兩個標簽(Label),兩個下拉組合框(Combo Box)和一個水平分隔符(Horizontal Spacer),先把它們放在對話框的任何地方。
7、 拖動群組框的右下角,把它拖動變大些,把上一步中其他控件移動到群組框中,按比例調整位置。當你按住鼠標左鍵將其他部件拖動到群組框內的時候,應該在群組框顯示出灰色的時候才松開鼠標,否則,有可能部件只是挨著群組框并沒有正確的放入其中。
8、 拖動第二個下拉組合框,將其寬度調整為第一個下拉框的二倍左右?,F在看起來的情況大概如下圖所示:
9、 將群組框的title屬性設置為“&Primary Key”,第一個標簽的text屬性設置為“Column:”,
第二個標簽的text屬性為“Order:”。
10、 右鍵單擊第一個組合框,從Qt設計師彈出的右鍵菜單的組合框編輯器中選擇“編輯項目”,
用文本“None”創建一個項目。
11、同樣的方式對第二個組合框創建兩個項目,項目為“Ascending”和“Descending”兩個項目,
即升序和降序排列。
12、右鍵單擊群組框,然后選擇“布局”?“柵格布局”。再次右鍵單擊群組框,并選擇“布局”
->“調整大小”,這個操作也可以通過單擊工具欄上的按鈕“”來完成,產生的布局如上圖2的右圖所示布局。
如果設計過程中出現錯誤,可以選擇 “編輯”?“撤銷”或者“打破布局”工具按鈕,重新進行布局。當然只要看起來不是很難看,也可以是其他的樣子,只要易于理解就是ok。
現在加入其它兩個群組框:Secondary Key和Teriary Key:
1、將對話框拖動到足夠大,以便能容納下另外兩個部分。
2、復制第一個組合框,粘貼兩次,依次拖動到下面。
3、把復制的兩個組合框的title屬性為“&Secondary Key”和“&Tertiary Key”。
4、創建一個垂直分隔符(Vertical Spacer),并將它放在Primary Key群組框和Secondary Key群組框的中間。
5、適當調整添加的控件的位置。
6、選擇對話框中的所有控件,降它們的布局設置為“柵格布局”,得到的效果應該如下圖3(a)。
7、單擊窗體,取消對窗口中任意控件的選擇,將整個對話框窗體的布局設置為“柵格布局”。然后向上和向左拖動窗體的右下角,將窗體變得盡可能小,設置兩個垂直空白的sizeHint屬性為[20,0]?,F在窗體應該像下圖3(b)所示:
最終的網格布局是4行2列,一共有8個單元格。如果你做出來的不是這樣,那么請撤銷布局,重新進行布局。
按照下圖命名每一個控件。命名對話框為 SortDialog,窗口標題為“Sort”。對各個控件進行命名,也就是修改控件的objectName屬性,最終結果如下圖4:
設置Tab順序,從上到下點擊下拉框,然后點擊Ok,Cancel,More按鈕。最終的順序如下圖(a):
以上是對話框的設計。然后用 Qt Designer建立控件的信號連接,單擊工具欄上的(即編輯信號/槽),切換到信號/槽的編輯狀態。將“確認”和“取消”按鈕連接到對話框的accept()和reject()槽函數。操作方法是點擊“確認按鈕”并拖動到對話框的空白處即可,然后在彈出的對話框中左邊點選clicked()信號,右邊點選accept()槽函數,如上圖(b)所示。同樣的方法將“取消”按鈕連接到reject()槽函數。
然后連接“更多”按鈕和secondaryGroupBox群組框,將按鈕的toggled(bool)信號和群組框的setVisible(bool)槽函數連接。同樣將“更多”按鈕與tertiaryGroupBox群組框setVisible(bool)槽函數連接。在連接的時候,可能看不到群組框的setVisible(boo)槽函數,這時在連接對話框(圖5(b))中點選“顯示從QWidget繼承的信號和槽”即可看到。
最終的連接情況如下圖6所示,我們可以在“信號/槽編輯器”中清楚地看到連接情況。
創建一個 sort目錄,將對話框保存到sort目錄下,文件名為:sortdialog.ui。
下面給這個窗體添加代碼,我們使用多繼承的方式使用這個對話框,也就是創建一個新的類來繼承QDialog類和這個窗體的類。
首先新建一個sortdialog.h頭文件,代碼如下:
然后新建sortdialog.cpp源文件:
1 #include <QtGui> 2 #include "sortdialog.h" 3 SortDialog::SortDialog(QWidget *parent):QDialog(parent) 4 { 5 setupUi(this); 6 secondaryGroupBox->hide(); 7 tertiaryGroupBox->hide(); 8 layout()->setSizeConstraint(QLayout::SetFixedSize); 9 setColumnRange('A', 'Z');10 }11 void SortDialog::setColumnRange(QChar first, QChar last)12 {13 primaryColumnCombo->clear();14 secondaryColumnCombo->clear();15 tertiaryColumnCombo->clear();16 secondaryColumnCombo->addItem(tr("None"));17 tertiaryColumnCombo->addItem(tr("None"));18 primaryColumnCombo->setMinimumSize(secondaryColumnCombo->sizeHint());19 QChar ch = first;20 while (ch <= last) {21 primaryColumnCombo->addItem(QString(ch));22 secondaryColumnCombo->addItem(QString(ch));23 tertiaryColumnCombo->addItem(QString(ch));24 ch = ch.unicode() + 1;25 }26 }
在構造函數中,隱藏了secondaryGroupBox和tertiaryGroupBox群組框部分。并設置對話框的sizeConstraint的屬性為QLayout::setFixedSize,這樣用戶不能隨便改變對話框的大小。
下面是main.cpp文件:
編譯運行這個程序,點擊“更多”按鈕,查看對話框的改變,結果應該與圖1一樣。另一種可以改變的對話框是多頁對話框。這類對話框也可以用兩種方式創建。相關的類有QTabWidget,QStackedWidget,QListWidget,QTreeWidget等。
新聞熱點
疑難解答