企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 7.2 子类化 QDialog 创建基于对话框的应用程序主要是使用子类化 QDialog 的方法。在本节,我们采用这个方法创建一个稍微复杂的实例-可扩展对话框。 可扩展对话框通常只显示简单的外观,但是它还有一个切换按钮( toggle button), 可以让用户在对话框的简单外观和扩展外观之间来回切换。 可扩展对话框通常用于试图同时 满足普通用户和高级用户需要的应用程序中,这种应用程序通常会隐藏那些高级选项,除非 用户明确要求看到它们。 这个对话框是一个用于电子制表软件应用程序的排序对话框( Sort 对话框),在这个 对话框中,用户可以选择一列或多列进行排序。在这个简单外观中,允许用户输入一个单一 的排序键,而在扩展外观下,还额外提供了两个排序键。 More 按钮允许用户在简单外观和 扩展外观之间切换。该实例的运行效果如图 7-2 所示。 ![](https://box.kancloud.cn/2016-01-22_56a1a150bc9a7.png)![](https://box.kancloud.cn/2016-01-22_56a1a150cd02c.png) ![](https://box.kancloud.cn/2016-01-22_56a1a150dd075.png) 图 7-2 实例运行效果 该实例名为 extensionDlg。共有以下原生源文件:工程文件 extensionDlg.pro,主程 序文件 main.cpp,对话框类 ExtensionDlg 的头文件 extensionDlg.h,实现文件 extensionDlg.cpp。 在第 6 章中我们向大家介绍了创建 Qt 应用程序的基本方法,这里我们采用 Qt Creator作为 IDE,并使用完全手写的方式完成程序的界面布局和构建。 首先当然是在 Qt Creator 中创建这个名为 extensionDlg 的项目,类型是 Empty Qt4 Project。然后在其中依次加入对话框类 ExtensionDlg 的头文件 extensionDlg.h,实现文件 extensionDlg.cpp,主程序文件 main.cpp 以及工程文件 extensionDlg.pro。这些文件的内容, 可以在 Qt Creator 的代码编辑器中完成编辑。 我们先看一下对话框类 ExtensionDlg 的头文件的内容。 ``` #ifndef EXTENSIONDLG_H #define EXTENSIONDLG_H #include <QtGui> class ExtensionDlg : public QDialog { Q_OBJECT public: ExtensionDlg(); void initBasicInfo(); void initDetailInfo(); public slots: void slot2Extension(); private: QWidget *baseWidget; QWidget *detailWidget; }; ``` 第 1 行引入 QtGui 模块的头文件 第 2 行声明我们的自定义对话框类 ExtensionDlg 单公有继承自 QDialog。 第 3 行加入 Q_OBJECT 宏,程序中用到诸如信号/槽等 Qt 核心机制的时候,都要加入这 个宏。 第 4-7 行声明了构造函数和初始化基础信息和扩展信息的函数。 第 8-9 行声明公有槽 slot2Extension(),它在用户点击【Detail】按钮时被触发。 第 10-12 行声明两个私有成员变量 baseWidget 和 detailWidget,它们都是 QWidget 的 实例,分别代表伸缩前后的对话框窗体。 再来看看 ExtensionDlg 的实现文件。 ``` #include "extensionDlg.h" ExtensionDlg::ExtensionDlg() { setWindowTitle(tr("Extension Dialog")); initBasicInfo(); initDetailInfo(); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(baseWidget); layout->addWidget(detailWidget); layout->setSizeConstraint(QLayout::SetFixedSize); layout->setSpacing(6); setLayout(layout); } void ExtensionDlg::initBasicInfo() { baseWidget = new QWidget; QLabel *nameLabel = new QLabel(tr("Name")); QLineEdit *nameEdit = new QLineEdit; QLabel *sexLabel = new QLabel(tr("Sex")); QComboBox *sexComboBox = new QComboBox; sexComboBox->addItem(tr("male")); sexComboBox->addItem(tr("female")); QPushButton *okButton = new QPushButton(tr("OK")); QPushButton *detailButton = new QPushButton(tr("Detail")); connect(detailButton,SIGNAL(clicked()),this,SLOT(slot2Extension())); QDialogButtonBox *btnBox = new QDialogButtonBox(Qt::Horizontal); btnBox->addButton(okButton,QDialogButtonBox::ActionRole); btnBox->addButton(detailButton,QDialogButtonBox::ActionRole); QFormLayout *formLayout = new QFormLayout; formLayout->addRow(nameLabel,nameEdit); formLayout->addRow(sexLabel,sexComboBox); QVBoxLayout *vboxLayout = new QVBoxLayout; vboxLayout->addLayout(formLayout); vboxLayout->addWidget(btnBox); baseWidget->setLayout(vboxLayout); } void ExtensionDlg::initDetailInfo() { detailWidget = new QWidget; QLabel *ageLabel = new QLabel(tr("Age")); QLineEdit *ageEdit = new QLineEdit; ageEdit->setText(tr("25")); QLabel *deptLabel = new QLabel(tr("Department")); QComboBox *deptComboBox = new QComboBox; deptComboBox->addItem(tr("department 1")); deptComboBox->addItem(tr("department 2")); deptComboBox->addItem(tr("department 3")); deptComboBox->addItem(tr("department 4")); QLabel *addressLabel = new QLabel(tr("address")); QLineEdit *addressEdit = new QLineEdit; QFormLayout *formLayout = new QFormLayout; formLayout->addRow(ageLabel,ageEdit); formLayout->addRow(deptLabel,deptComboBox); formLayout->addRow(addressLabel,addressEdit); detailWidget->setLayout(formLayout); detailWidget->hide(); } void ExtensionDlg::slot2Extension() { if (detailWidget->isHidden()) { detailWidget->show(); } else { detailWidget->hide(); } } ``` 第 1-9 句是构造函数中的内容。 第 1 句设置应用程序的标题。 第 2 句调用 initBasicInfo()函数,初始化基本信息船窗体。 第 3 句调用 initDetailInfo()函数,初始化扩展信息窗体。 第 4-9 句设置窗体的布局。 第 4 句定义一个垂直布局类实体 layout。 第 5、6 两句,分别将 baseWidget 和 detailWidget 加入到布局中。 第 7、8 两句对于布局管理来说是非常常见的用法,必须熟练掌握。其中 setSizeConstraint()函数用于设置窗体的缩放模式,其默认取值是 QLayout::SetDefaultConstraint。这里取参数值为 Qlayout::SetFixedSize 是为了使窗体 的大小固定,不可经过鼠标拖动而改变大小;如果不这样设置,当用户再次点击 【Detail】按钮时,对话框将不能恢复到初始状态。 setSpacing()函数用于设置位于布局之中的窗口部件之间的间隔大小。 这里暂时不对布局管理的相关内容展开讲解,在《布局管理》这一章中将有详细的介绍。 第 9 句将刚刚设置好的布局应用加载到窗体上。 第 10-29 句是 initBasicInfo()函数体的内容。 第 10 句实例化 baseWiaget,注意 baseWidget 是全局变量。 第 11-18 句,依次定义窗体中的部件,注意在输入字符时,前面都加上了 tr()函数。 第 19 句对于整个程序来说是关键,它使用信号 /槽机制连接了 detailButton 的单击信号和窗口类 ExtensionDlg 的 slot2Extension()函数,这就使得整个对话框变得可伸缩。 第 20-22 行示范了 QDialogButtonBox 类的用法,它用于创建一个符合当前窗口部件样 式的一组按钮,并且它们被排列在某种布局之中。在 Qt Designer 中,最为常见的用法是 从窗口部件盒里面把默认的那个 QDialogButtonBox 窗口部件拖到界面上来,不过显然这并 不如使用代码来得方便。 第 20 行的 Qt::Horizontal 实参表示创建水平方向的按钮组合。 第 21、22 两行把两个按钮加入到这个组合之中。其中的 QDialogButtonBox::ActionRole 参数表示创建的按钮具有实际的功能,单击它可以引起对话框的某种变化。该参数可以有很 多不同的值,使得这些按钮具有不同的功能,它们都被包含在 QDialogButtonBox::ButtonRole 这个枚举值之中。 第 23-29 行设置窗体的布局。窗体的顶级布局是一个垂直布局,而其中嵌套了一个表 单布局。 第 23-25 行是设置表单布局的常用方法,表单布局常用于窗体界面元素可以整齐的分 成两列的情况。addRow()方法用于向布局中加入整行的界面元素。 第 26-29 行定义窗体的顶级布局,并将其两个元素 formLayout 和 btnBox 依次加入其中。 小贴士:布局也是一种窗口部件,认识到这一点很关键。 第 30-47 行定义了 initDetailInfo()函数。其实现过程与 initBasicInfo()函数大同 小异。只是需要注意第 47 行,正是由于对 detailWidget 调用了 hide()函数,才使得程序 初始时,显示的是基本信息,而将扩展信息隐藏了起来。 hide()函数用于将窗口隐藏起来, 它是 Qt 默认的槽函数之一,其原型如下: ``` void QWidget::hide () [slot] ``` 它的作用等同于调用 setVisible(false)函数。 第 48-55 行定义了 slot2Extension()函数。前面讲到,它是我们自定义的槽函数,在 点击【Detail】按钮时,将被触发。它的内容很简单,就是判断扩展窗口是否被隐藏,如果被隐藏,就显示它;否则就隐藏它。 isHidden()函数用于判断窗体的显示窗体的显隐状态。 然后就可以像下面这样书写主函数。第 1 句是必需的。第 2-4 句定义 ExtensionDlg 的 对象,并模态的显示这个窗体。 ``` #include <QApplication> #include "extensionDlg.h" int main(int argc, char * argv[]) { QApplication app(argc,argv); ExtensionDlg exDlg; exDlg.show(); return app.exec(); } ``` 最后就是书写项目文件 ExtensionDlg.pro 了。 ``` TEMPLATE = app TARGET = DEPENDPATH += . INCLUDEPATH += . # Input HEADERS += extensionDlg.h SOURCES += extensionDlg.cpp main.cpp ``` 第 1 句,表示程序的类型是 app。 第 2 句中 TARGET 指定可执行文件或库的基本文件名,其中不包含任何的扩展、前缀或 版本号,默认的就是当前的目录名。 第 4 句中,INCLUDEPATH 指定 C++编译器搜索全局头文件的路径。 第 5 句是注释。 第 6 句中,HEADERS 指定工程的 C++头文件(.h)。多个头文件的情况下,用空格隔 开。 第 7 句中,SOURCES 指定工程的 C++实现文件(.cpp),多个头文件的情况下,用空格隔开。 qmake 的语法规则是比较简明的,详细情况请参阅附录。 好了,到此我们就完成了使用子类化的方法创建自定义对话框窗口程序。这其中有几点还想再强调一下,一是要明白所谓子类化自 QDialog 类就是指通过继承自 QDialog 类来创建自定义的对话框类;二是要知道如果程序中用到了 Qt 的核心机制(如信号/槽),不 要忘记在类的声明处的第一行加入 Q_OBJECT 宏;三是要掌握判断和控制显隐对话框的方法;四是掌握定义窗口界面元素的方法(先定义,再设置其属性);五是了解布局管理的基本方法(后面还会学到);六是要掌握书写工程文件的基本方法。七是掌握 Qt Creator 的基本用法。 在下一节,我们将采用 Qt Designer 完成这个程序界面的布局,大家将会了解到,有 时候使用 Qt Designer 设计界面会方便一些。