第八章 Qt GUI之对话框使用

第八章 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 QDialog
11 {
12     Q_OBJECT
13     
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布局安装在FindDialog
42 
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     else
56     {
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 QDialog
11 {
12     Q_OBJECT
13     
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、QRegExpValidator
13 
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、 拖动第二个下拉组合框,将其宽度调整为第一个下拉框的二倍左右。现在看起来的情况大概如下图所示:

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]。现在窗体应该像下图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等。

原文地址:https://www.cnblogs.com/heguoyuan/p/4280336.html