在 Qt Creator 中新建一个 Widget Application 项目 samp2_1,在选择窗口基类的页面选择 QWidget 作为窗体基类,并选中“Generate form”复选框。创建后的项目文件目录树如图 1 所示。
这个项目包含以下一些文件:
项目管理文件 samp2_1.pro,存储项目设置的文件。
主程序入口文件 main.cpp,实现 main()函数的程序文件。
窗体界面文件 widget.ui,一个 XML 格式存储的窗体上的元件及 其布局的文件。
widget.h 是所设计的窗体类的头文件,widget.cpp 是 widget.h 里 定义类的实现文件。C++ 中,任何窗体或界面组件都是用类封装的,一个类一般有一个头文件(.h 文件)和一个源程序文件(.cpp 文件)。
后缀为“.pro”的文件是项目的管理文件,文件名就是项目的名称,如本项目中的 samp2_1.pro。 下面是 samp2_1.pro 文件的内容。
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = samp2_1
TEMPLATE = app
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
项目管理文件用于记录项目的一些设置,以及项目包含文件的组织管理。
“Qt += core gui”表示项目中加入 core gui 模块。core gui 是 Qt 用于 GUI 设计的类库模块,如果创建的是控制台(Console)应用程序,就不需要添加 core gui。
Qt 类库以模块的形式组织各种功能的类,根据项目涉及的功能需求,在项目中添加适当的类库模块支持。例如,如果项目中使用到了涉及数据库操作的类就需要用到 sql 模块,在 pro 文件中需要增加如下一行:
Qt +=sql
samp2_1.pro 中的第 2 行是:
greaterThan(Qt_MAJOR_VERSION, 4): Qt += widgets
这是个条件执行语句,表示当 Qt 主版本大于 4 时,才加入 widgets 模块。
“TARGET = samp2_1”表示生成的目标可执行文件的名称,即编译后生成的可执行文件是 samp2_1.exe。
“TEMPLATE = app”表示项目使用的模板是 app,是一般的应用程序。
后面的 SOURCES、HEADERS、FORMS 记录了项目中包含的源程序文件、头文件和窗体文件(.ui 文件)的名称。这些文件列表是 Qt Creator 自动添加到项目管理文件里面的,用户不需要手动修改。当添加一个文件到项目,或从项目里删除一个文件时,项目管理文件里的条目会自动修改。
Qt 项目中,后缀为“.ui”的文件是可视化设计的窗体的定义文件,如 widget.ui。双击项目文件目录树中的文件 widget.ui,会打开一个集成在 Qt Creator 中的 Qt Designer 对窗体进行可视化设计,如图 1 所示。
后面将称这个集成在 Qt Creator 中的 Qt Designer 为“UI 设计器”,以便与独立运行的 Qt Designer 区别开来。
图 2 显示的是选中窗体上放置的标签组件后属性编辑器的内容。最上方显示的文字“LabDemo: QLabel”表示这个组件是一个 QLabel 类的组件,objectName 是LabDemo。
属性编辑器的内容分为两列,分别为属性的名称和属性的值。属性又分为多个组,实际上表示了类的继承关系,如在图 2 中,可以看出 QLabel 的继承关系是QObject→QWidget→QFrame→QLabel。
objectName 表示组件的对象名称,界面上的每个组件都需要一个唯一的对象名称,以便被引用。界面上的组件的命名应该遵循一定的法则,具体使用什么样的命名法则根据个人习惯而定,主要目的是便于区分和记忆,也要便于与普通变量相区分。
设置其他属性的值只需在属性编辑器里操作即可,如设置 LabDemo 的 text 属性为“Hello,World”,只需像图 2 那样修改 text 属性的值即可。
提示,标准 C++ 语言里并没有 property 关键字,property 是 Qt 对标准 C++ 的扩展,使得在 Qt Designer 里就可以可视化设置类的数据。
在信号与槽编辑器的工具栏上单击“Add”按钮,在出现的条目中,Sender 选择 btnClose,Signal 选择 clicked(),Receiver 选择窗体 Widget,Slot 选择 close()。这样设置表示当按钮 btnClose 被单击时,就执行 Widget 的 close() 函数,实现关闭窗口的功能。
标签的文字内容和字体被修改了,窗口标题也显示为所设置的标题,而我们并没有编写一行程序语句,Qt 是怎么实现这些功能的呢?
为了搞清楚窗体类的定义,以及界面功能的实现原理,这里将项目进行编译。编译后在项目目录下会自动生成一个文件 ui_widget.h,这样对于一个窗体,就有 4 个文件了,各文件的功能说明见表 6。
widget.h 文件是窗体类的头文件。在创建项目时,选择窗体基类是 QWidget,在 widget.h 中定义了一个继承自 QWidget 的类 Widget。
下面是 widget.h 文件的内容:
#ifndef WIDGET_H
#define WIDGET_H
#include
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.h 文件有几个重要的部分。
namespace 声明
代码中有如下的一个 namespace 声明:
namespace Ui {
class Widget;
}
这是声明了一个名称为 Ui 的命名空间(namespace),包含一个类 Widget。但是这个类 Widget 并不是本文件里定义的类 Widget,而是 ui_widget.h 文件里定义的类,用于描述界面组件的。这个声明相当于一个外部类型声明(具体要看完 ui_widget.h 文件内的解释之后才能搞明白)。
Widget 类的定义
widget.h 文件的主体部分是一个继承于 QWidget 的类 Widget 的定义,也就是本实例的窗体类。
在 Widget 类中使用了宏 Q_OBJECT,这是使用 Qt 的信号与槽(signal 和 slot)机制的类都必须加入的一个宏(信号与槽在后面详细介绍)。
在 public 部分定义了 Widget 类的构造函数和析构函数。
在 private 部分又定义了一个指针。
Ui::Widget *ui;
这个指针是用前面声明的 namespace Ui 里的 Widget 类定义的,所以指针 ui 是指向可视化设计的界面,后面会看到要访问界面上的组件,都需要通过这个指针 ui。
widget.cpp 文件
widget.cpp 文件是类 Widget 的实现代码,下面是 widget.cpp 文件的内容
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
注意到,在这个文件的包含文件部分自动加入了如下一行内容:
#include "ui_widget.h"
这个就是 Qt 编译生成的与 UI 文件 widget.ui 对应的类定义文件。
目前只有构造函数和析构函数。其中构造函数头部是:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
其意义是:执行父类 QWidget 的构造函数,创建一个 Ui::Widget 类的对象 ui。这个 ui 就是 Widget 的 private 部分定义的指针变量 ui。
构造函数里只有一行语句:
ui->setupUi(this)
它是执行了 Ui::Widget 类的 setupUi() 函数,这个函数实现窗口的生成与各种属性的设置、信号与槽的关联(后面会具体介绍)。
析构函数只是简单地删除用 new 创建的指针 ui。
所以,在 ui_widget.h 文件里有一个 namespace 名称为 Ui,里面有一个类 Widget 是用于描述可视化设计的窗体,且与 widget.h 里定义的类同名。在 Widget 类里访问 Ui::Widget 类的成员变量或函数需要通过 Widget 类里的 ui 指针,如同构造函数里执行 ui->setupUi( this) 函数那样。
widget.ui 是窗体界面定义文件,是一个 XML 文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由 Qt 自动解析,并以 XML 文件的形式保存下来。在设计界面时,只需在 UI 设计器里进行可视化设计即可,而不用管 widget.ui 文件是怎么生成的。
下面是 widget.ui 文件的内容:
Widget
0
0
336
216
My First Demo
100
70
141
61
12
75
true
Hello,World
210
150
75
23
Close
btnClose
clicked()
Widget
close()
247
161
167
107
ui_widget.h 是在对 widget.ui 文件编译后生成的一个文件,ui_widget.h 会出现在编译后的目录下,或与 widget.ui 同目录(与项目的 shadow build 编译设置有关)。
文件 ui_widget.h 并不会出现在 Qt Creator 的项目文件目录树里,当然,可以手工将 ui_widget.h 添加到项目中。方法是在项目文件目录树上,右击项目名称节点,在调出的快捷菜单中选择“Add Existing Files…”,找到并添加 ui_widget.h 文件即可。
注意,ui_widget.h 是对 widget.ui 文件编译后自动生成的,widget.ui 又是通过 UI 设计器可视化设计生成的。所以,对 ui_widget.h 手工进行修改没有什么意义,所有涉及界面的修改都应该直接在UI 设计器里进行。所以,ui_widget.h 也没有必要添加到项目里。
下面是 ui_widget.h 文件的内容:
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.9.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_WIDGET_H
#define UI_WIDGET_H
#include
#include
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
class Ui_Widget
{
public:
QLabel *label;
QPushButton *btnClose;
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName(QStringLiteral("Widget"));
Widget->resize(336, 216);
label = new QLabel(Widget);
label->setObjectName(QStringLiteral("label"));
label->setGeometry(QRect(100, 70, 141, 61));
QFont font;
font.setPointSize(12);
font.setBold(true);
font.setWeight(75);
label->setFont(font);
btnClose = new QPushButton(Widget);
btnClose->setObjectName(QStringLiteral("btnClose"));
btnClose->setGeometry(QRect(210, 150, 75, 23));
retranslateUi(Widget);
QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QApplication::translate("Widget", "My First Demo", Q_NULLPTR));
label->setText(QApplication::translate("Widget", "Hello\357\274\214World", Q_NULLPTR));
btnClose->setText(QApplication::translate("Widget", "Close", Q_NULLPTR));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
查看 ui_widget.h 文件的内容,发现它主要做了以下的一些工作:
1、定义了一个类 Ui_Widget,用于封装可视化设计的界面。
2、自动生成了界面各个组件的类成员变量定义。在 public 部分为界面上每个组件定义了一个指针变量,变量的名称就是设置的 objectName。比如,在窗体上放置了一个 QLabel 和一个 QPushButton 并命名后,自动生成的定义是:
QLabel *LabDemo;
QPushButton *btnClose;
3、定义了 setupUi() 函数,这个函数用于创建各个界面组件,并设置其位置、大小、文字内容、字体等属性,设置信号与槽的关联。setupUi() 函数体的第一部分是根据可视化设计的界面内容,用 C++ 代码创建界面上各组件,并设置其属性。
接下来,setupUi() 调用了函数 retranslateUi(Widget),用来设置界面各组件的文字内容属性,如标签的文字、按键的文字、窗体的标题等。将界面上的文字设置的内容独立出来作为一个函数 retranslateUi(),在设计多语言界面时会用到这个函数。
setupUi() 函数的第三部分是设置信号与槽的关联,本文件中有以下两行:
QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);
第1 行是调用 connect() 函数,将在 UI 设计器里设置的信号与槽的关联转换为语句。这里是将 btnClose 按键的 clicked() 信号与窗体 Widget 的 close() 槽函数关联起来,就是在图 4 中设置的信号与槽的关联的程序语句实现。这样,当单击 btnClose 按钮时,就会执行 Widget 的 close() 槽函数,而 close() 槽函数的功能是关闭窗口。
第 2 行是设置槽函数的关联方式,用于将 UI 设计器自动生成的组件信号的槽函数与组件信号相关联。
所以,在Widget 的构造函数里调用 ui->setupUI(this),就实现了窗体上组件的创建、属性设置、信号与槽的关联。
定义 namespace Ui,并定义一个从Ui_Widget 继承的类Widget。
namespace Ui {
class Widget: public Ui_Widget {};
}
提示:ui_widget.h 文件里实现界面功能的类是 Ui_Widget。再定义一个类 Widget 从 Ui_Widget 继承而来,并定义在 namespace Ui 里,这样 Ui:: Widget 与 widget.h 里的类 Widget 同名,但是用 namespace 区分开来。所以,界面的 Ui:: Widget 类与文件 widget.h 里定义的 Widget 类实际上是两个类,但是 Qt 的处理让用户感觉不到 Ui:: Widget 类的存在,只需要知道在 Widget 类里用 ui 指针可以访问可视化设计的界面组件就可以了。
Qt探秘——谈ui文件的用法
https://www.cnblogs.com/findumars/p/5104232.html
Qt之UI文件设计和运行机制
https://blog.csdn.net/zhizhengguan/article/details/81557646
main.cpp 是实现 main() 函数的文件,下面是 main.cpp 文件的内容。
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv); //定义并创建应用程序
Widget w; //定义并创建窗口
w.show(); //显示窗口
return a.exec(); //应用程序运行
}
main() 函数是应用程序的入口。它的主要功能是创建应用程序,创建窗口,显示窗口,并运行应用程序,开始应用程序的消息循环和事件处理。
QApplication 是 Qt 的标准应用程序类,第 1 行代码定义了一个 QApplication 类的实例 a,就是应用程序对象。
然后定义了一个 Widget 类的变量 w,Widget 是本实例设计的窗口的类名,定义此窗口后再用 w.show() 显示此窗口。
最后一行用 a.exec() 启动应用程序的执行,开始应用程序的消息循环和事件处理。
本节再以一个稍微复杂的例子来讲解设计 GUI 的常见功能,包括界面设计时布局的管理,以及程序里如何访问界面组件。
实例程序功能
创建一个 Widget Application 项目 samp2_2,在创建窗体时选择基类 QDialog,生成的类命名为 QWDialog,并选择生成窗体。
如此新建的项目 samp2_2 有一个界面文件 qwdialog.ui,一个头文件 qwdialog.h 和源程序文件 qwdialog.cpp。此外,还有项目文件 samp2_2.pro 和主程序文件 main.cpp。
qwdialog.ui 界面文件设计时界面如图 1 所示。程序的主要功能是对中间一个文本框的文字字体样式和颜色进行设置。
在界面设计时,对需要访问的组件修改其 objectName,如各个按钮、需要读取输入的编辑框、需要显示结果的标签等,以便在程序里区分。对于不需要程序访问的组件则无需修改其 objectName,如用于界面上组件分组的 GroupBox、Frame、布局等,让 UI 设计器自动命名即可。
对于界面组件的属性设置,需要注意以下几点。
objectName 是窗体上创建的组件的实例名称,界面上的每个组件需要有一个唯一的 objectName,程序里访问界面组件时都是通过其 objectName 进行访问,自动生成的槽函数名称里也有 objectName。所以,组件的 objectName 需要在设计程序之前设置好,设置好之后一般不要再改动。若设计程序之后再改动 objectName,涉及的代码需要相应的改动。
窗体的 objectName 就是窗体的类名称,在 UI 设计器里不要修改窗体的 objectName,窗体的实例名称需要在使用窗体的代码里去定义。
界面组件布局
Qt 的界面设计使用了布局(Layout)功能。所谓布局,就是界面上组件的排列方式,使用布局可以使组件有规则地分布,并且随着窗体大小变化自动地调整大小和相对位置。布局管理是 GUI 设计的必备技巧,下面逐步讲解如何实现图 1 所示的界面设计。
界面组件的层次关系
为了将界面上的各个组件的分布设计得更加美观,经常使用一些容器类,如 QgoupBox、QtabWidget、QFrame 等。
例如,将 3 个 CheckBox 组件放置在一个 GroupBox 组件里,该 GroupBox 组件就是这 3 个 CheckBox 的容器,移动这个 GroupBox 就会同时移动其中的 3 个 CheckBox。
Qt 为界面设计提供了丰富的布局管理功能,在 UI 设计器中,组件面板里有 Layouts 和 Spacers 两个组件面板,在窗体上方的工具栏里有布局管理的按钮(如图 4 所示)。
使用组件面板里的布局组件设计布局时,先拖放一个布局组件到窗体上,如在设计图 4 中 3 个按钮的布局时,先放一个 Horizontal Layout 到窗体上,布局组件会以红色边框显示。再往布局组件里拖放 3 个 Push Button 和 2 个 Horizontal Spacer,就可以得到图 1 中 3 个按钮的水平布局效果
在设计窗体的上方有一个工具栏,用于调整设计器进入不同的状态,以及进行布局设计,工具栏上各按钮的功能见表 6。
使用工具栏上的布局控制按钮时,只需在窗体上选中需要设计布局的组件,然后点击某个布局按钮即可。在窗体上选择组件时同时按住 Ctrl 键,可以实现组件多选,选择某个容器类组件,相当于选择了其内部的所有组件。
例如,在图 3 的界面中,选中 groupBox1,然后单击“Lay Out Horizontally”工具栏按钮,就可以对 groupBox1 内的 3 个 CheckBox 水平布局。
在图 4 的界面上,使 groupBox1 里的 3 个 CheckBox 水平布局,groupBox2 里的 3 个 RadioButton 水平布局,下方 3个按钮水平布局。在窗体上又放置了一个 PlainTextEdit 组件。现在,改变 groupBox1、groupBox2 或按钮的水平布局的大小,其内部组件都会自动改变大小。但是当改变窗体大小时,界面上的各组件却并不会自动改变大小。
随后还需为窗体指定一个总的布局。选中窗体(即不要选择任何组件),单击工具栏上的“Lay Out Vertically”按钮,使 4 个组件垂直分布。这样布局后,当窗体大小改变时,各个组件都会自动改变大小。
在 UI 设计器里可视化设计布局时,要善于利用水平和垂直空格组件,善于设置组件的最大、最小宽度和高度来实现某些需要的布局效果。
伙伴关系与 Tab 顺序
在 UI 设计工具栏上单击“Edit Buddies”按钮可以进入伙伴关系编辑状态,如设计一个窗体时,进入伙伴编辑状态之后的界面如图 7 所示。
伙伴关系(Buddy)是指界面上一个 Label 和一个组件相关联,如图 7 中的伙伴关系编辑状态,单击一个 Label,按住鼠标左键,然后拖向一个组件,就建立了 Label 和组件之间的伙伴关系。
伙伴关系是为了在程序运行时,在窗体上用快捷键快速将输入焦点切换到某个组件上。例如,在图 7 的界面上,设定“姓名”标签的 Text 属性为“姓名(&N)”,其中符号“&”用来指定快捷字符,界面上并不显示“&”,这里指定快捷字母为 N。那么程序运行时,用户按下 Alt+N,输入焦点就会快速切换到“姓名”关联的输入框内。
在 UI 设计器工具栏上单击“Edit Tab Order”按钮进入Tab 顺序编辑状态(如图 8 所示)。Tab 顺序是指在程序运行时,按下键盘上的 Tab 键时输入焦点的移动顺序。一个好的用户界面,在按 Tab 键时,焦点应该以合理的顺序在界面上移动,而不是随意地移动。
进入 Tab 顺序编辑状态后,在界面上会显示具有 Tab 顺序组件的编号,依次按希望的顺序单击组件,就可以重排 Tab 顺序了。没有输入焦点的组件是没有 Tab 顺序的,如 Label 组件。
项目功能实现
下面开始设计程序功能。对于该程序,希望它的功能如下:
单击 UnderLine、Italic、Bold 3 个 CheckBox 时,根据其状态,设置 PlainTextEdit 里的文字的字体样式;
Black、Red、Blue 3 个 RadioButton 是互斥选择的,单击某个 RadioButton 时,设置文字的颜色;
单击“确定”“取消”或“退出”按钮时,关闭窗口,退出程序。
字体样式设置
窗体在设计模式下,选中 chkBoxUnder 组件,单击右键调出其快捷菜单。在快捷菜单中单击菜单项“Go to slot…”(中文状态为“转到槽”),出现如图 9 所示的对话框。
该对话框列出了 QCheckBox 类的所有信号,第一个是 clicked(),第二个是带一个布尔类型参数的 clicked(bool)。
信号 clicked(bool) 会将 CheckBox 组件当前的选择状态作为一个参数传递,在响应代码里可以直接利用这个传递的参数。而如果用信号 clicked(),则需要在代码里读取 CheckBox 组件的选中状态。为了简化代码,选择 clicked(bool) 信号。
选择 clicked(bool),然后单击“OK”按钮,在 QWDialog 的类定义中,会在 private slots 部分自动增加一个槽函数声明,函数名是根据发射对象及其信号名称自动命名的。
void on_chkBoxUnder_clicked(bool checked);
同时,在 qwdialog.cpp 文件中自动添加了函数 on_chkBoxUnder_clicked(bool) 的框架,在此函数中添加如下的代码,实现文本框字体下划线的控制。
void QWDialog::on_chkBoxUnder_clicked(bool checked)
{
QFont font=ui->txtEdit->font();
font.setUnderline(checked);
ui->txtEdit->setFont(font);
}
以同样的方法为 Italic 和 Bold 两个 CheckBox设计槽函数,编译后运行,发现已经实现了修改字体的下划线、斜体、粗体属性的功能,说明信号与槽函数已经关联了。
但是,查看 QWDialog 的构造函数,构造函数只有简单的一条语句。
QWDialog::QWDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QWDialog)
{
ui->setupUi(this);
}
这里没有发现用 connect() 函数进行几个 CheckBox 的信号与槽函数关联的操作。这些功能是如何实现的呢?
查看编译生成的 ui_qwdialog.h 文件。构造函数里调用的 setupUi() 是在 ui_qwdialog.h 文件里实现的。查看 setupUi() 函数的内容,也没有发现用 connect() 函数进行几个 CheckBox 的信号与槽关联的操作,只是在 setupUI()里发现了如下的一条语句:
QMetaObject::connectSlotsByName(QWDialog);
秘密就在于这条语句。connectSlotsByName(QWDialog) 函数将搜索 QWDialog 界面上的所有组件,将信号与槽函数匹配的信号和槽关联起来,它假设槽函数的名称是:
void on_
例如,通过 UI 设计器的操作,为 chkBoxUnder 自动生成的槽函数是:
void on_chkBoxUnder_clicked(bool checked);
它就正好是 chkBoxUnder 的信号 clicked(bool) 的槽函数。那么,connectSlotsByName() 就会将此信号和槽函数关联起来,如同执行了下面的这样一条语句:
connect(chkBoxUnder, SIGNAL(clicked (bool)),
this, SLOT (on_chkBoxUnder_clicked (bool));
这就是用 UI 设计器可视化设计某个组件的信号响应槽函数,而不用手工去将其关联起来的原因,都是在界面类的构造函数里调用 setupUi() 自动完成了关联。
字体颜色设置
设置字体的 3 个 RadioButton 是互斥性选择的,即一次只有一个 RadioButton 被选中,虽然也可以采用可视化设计的方式设计其 clicked() 信号的槽函数,但是这样就需要生成 3 个槽函数。这里可以简化设计,即设计一个槽函数,将 3 个 RadioButton 的 clicked() 信号关联到这一个槽函数。
为此,在 QWDialog 类的 private slots 部分增加一个槽函数定义如下:
void setTextFontColor();
提示 将鼠标光标移动到这个函数的函数名上面,单击右键,在弹出的快捷菜单中选择“Refactor”→“Add Definition in qwdialog.cpp”,就可以在 qwdialog.cpp 文件中自动为函数 setTextFontColor() 生成一个函数框架。
在 qwdialog.cpp 文件中,为 setTextFontColor() 编写实现代码如下:
void QWDialog::setTextFontColor()
{
QPalette plet=ui->txtEdit->palette();
if (ui->rBtnBlue->isChecked())
plet.setColor(QPalette::Text,Qt::blue);
else if (ui->rBtnRed->isChecked())
plet.setColor(QPalette::Text,Qt::red);
else if (ui->rBtnBlack->isChecked())
plet.setColor(QPalette::Text,Qt::black);
else
plet.setColor(QPalette::Text,Qt::black);
ui->txtEdit->setPalette(plet);
}
由于这个槽函数是自定义的,所以不会自动与 RadioButton 的 clicked() 事件关联,此时编译后运行程序不会实现改变字体颜色的功能。需要在 QWDialog 的构造函数中手工进行关联,代码如下:
QWDialog::QWDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QWDialog)
{
ui->setupUi(this);
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
}
在构造函数中将 3 个 RadioButton 的 clicked() 信号与同一个槽函数 setTextFontColor() 相关联。再编译后运行,就可以更改文字的颜色了。
三个按钮的功能设计
界面上还有“确定”“取消”“退出”3 个按钮,这是在对话框中常见的按钮。“确定”表示确认选择并关闭对话框,“取消”表示取消选择并关闭对话框,“退出”则直接关闭对话框。
QWDialog 是从 QDialog 继承而来的,QDialog 提供了 accept()、reject()、close() 等槽函数来表示这三种状态,只需将按钮的 clicked() 信号与相应槽函数关联即可。
下面采用可视化的方式,将按钮的 clicked() 信号与这些槽函数关联起来。在 UI 设计器里,单击上方工具栏里的“Edit Signals/Slots”按钮,窗体进入信号与槽函数编辑状态,如图 10 所示。
将鼠标移动到“确定”按钮上方,再按下鼠标左键,移动到窗体的空白区域释放左键,这时出现如图 11 所示的关联设置对话框。
在图 11 中,左侧的列表框里显示了 btnOK 的信号,选择 clicked(),右边的列表框里显示了 QWDialog 的槽函数,选择 accept(),单击“OK”按钮。
同样的方法可以将 btnCancel 的 clicked() 信号与 QWDialog 的 reject() 槽函数关联,将 btnClose 的 clicked() 信号与 QWDialog 的 close() 槽函数关联。
注意,在图 11 的右侧列表框中没有 close() 槽函数,需要勾选下方的“Show signals and slots inherited from QWidget”才会出现 close() 函数。
设置完 3 个按钮的信号与槽关联之后,在窗体下方的 Signals 和 Slots 编辑器里也显示了这 3 个关联。实际上,可以直接在 Signals 和 Slots 编辑器进行关联设置。现在编译并运行程序,单击这 3 个按钮都会关闭程序。
那么,这 3 个按钮的信号与槽函数的关联是在哪里实现的呢?答案在 setupUi() 函数里,在 setupUi() 函数里自动增加了以下 3 行代码:
QObject::connect(btnOK, SIGNAL(clicked()), QWDialog, SLOT(accept()));
QObject::connect(btnCancel, SIGNAL(clicked()), QWDialog, SLOT(reject()));
QObject::connect(btnClose, SIGNAL(clicked()), QWDialog, SLOT(close()));
这个实例程序的功能全部完成了。采用 UI 设计器设计了窗体界面,采用可视化和程序化的方式设计槽函数,设计信号与槽函数之间的关联。
从以上的设计过程可以看到,Qt Creator 和 UI 设计器为设计应用程序提供了强大的可视化设计功能。