Qt学习第三章——Qt框架功能概述
Qt框架中的模块
Qt框架中的模块分为两大类:
- Qt基本模块(Qt Essentials):提供了Qt 在所有平台上的基本功能。
- Qt附加模块(Qt Add-Ons):实现一些特定功能的模块。
基本模块:
模块 | 描述 |
---|---|
Qt Core | Qt框架的核心,定义了元对象系统 |
Qt GUI | 设计 GUI 界面的基础类,包括事件处理、文字处理等 |
Qt Widgets | 提供用于创建GUI的各种界面组件类 |
Qt D-Bus | D-Bus是实现进程间通信 (inter process communication,IPC)和远程过程调用(remote procedure call,RPC)的一种通信协议 |
Qt Test | 提供一些对应用程序和库进行单元测试的类 |
Qt QML | 提供用QML编程的框架,定义了QML和基础引擎 |
Qt Quick | 用于开发QML应用程序的标准库,提供创建UI的一些基本类型 |
Qt Quick Controls | 提供一套基于Qt Quick的控件,可用于创建复杂的UI |
Qt Quick Dialogs | 提供通过QML使用系统对话框的功能 |
Qt Quick Layouts | 提供用于管理界面布局的QML类型 |
Qt Quick Test | 提供QML应用程序的单元测试框架 |
其他模块都依赖于Qt Core模块,使用qmake 构建GUI项目时,qmake项目配置文件中会自动加入QT += core gui
其他模块一般不会被自动加入,在项目中使用某个模块,可以在项目配置中添加:
1
2
QT += multimedia multimediawidgets
QT += sql
全局定义
<QtGlobal>
头文件(Qt类的头文件都会包含该文件)包含了Qt类库的一些全局定义:
- 基本数据类型
- 函数
- 宏
全局函数定义
函数 | 功能 |
---|---|
T aABS(const T &value) | 返回变量 value 的绝对值 |
const T &qBound(const T &min, const T &value, const T &max) | 返回value限定在 min 至 max 范围之内的值 |
T qExchange(T &obj, U &&newValue) | 将obj的值用newValue替换,返回obj的旧值 |
int qFpClassify(double val) | 返回val的分类(非数、正或负无穷、零) |
bool qFuzzyCompare(double p1, double p2) | 若p1和p2近似相等,返回true |
bool qFuzzyIsNull(double d) | 如果参数 d 约等于0,返回 true |
double qInf() | 返回无穷大的数 |
double qIsFinite(double d) | 若d是一个有限的数,返回 true |
bool qIsInf(double d) | 若d是一个无限大的数,返回true |
bool qIsNaN(double d) | 若d 不是一个数,返回true |
const T &qMax(const T &value1, const T &value2) | 返回 value1 和 value2 中较大的值 |
const T &qMin(const T &value1, const T &value2) | 返回 value1 和 value2 中较小的值 |
qint64 qRound64(double value) | 将 value 近似最接近的 qint64 整数 |
int qRound(double value) | 将 value 近似为最接近的 int 整数 |
还有一些基础的数学运算函数在
<QtMath>
头文件中定义,比如三角运算函数、弧度与角度之间的转换函数等。
宏定义
qDebug(const char *message, ...)
:在debugger窗体显示信息QT_VERSION
:这个宏展开为数值形式0xMMNNPP(MM = major,NN = minor,PP = patch)表示Qt编译器的版本
1
2
QString str;
qDebug() << str.asprintf("0X%oX", QT_VERSION)
QT_VERSION_STR
:这个宏展开为Qt版本号的字符串
1
qDebug() << QT_VERSION_STR;
Q_BYTE_ORDER
、Q_BIG_ENDIAN
和Q_LITTLE_ENDIAN
:分别表示系统内存中数据的字节序,大端字节序、小端字节序。在需要判断系统字节序时会用到
1
2
3
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
...
#endif
Q_DECL_IMPORT
和Q_DECL_EXPORT
:在使用或设计共享库时,用于导入或导出库的内容,后续章节有其使用的实例Q_UNUSED(name)
:这个宏用于在函数中定义不在函数体里使用的参数
1
2
3
4
5
void MainWindow::on_imageSaved(int id, const QString &fileName)
{
Q_UNUSED(id);
LabInfo->setText("图片保存为:" + fileName);
}
foreach(variable, container)
:用于容器类的遍历
1
2
foreach(const QString &codecName, recorder->supportedAudioCodecs())
ui->comboCodec->addItem(codecName);
Qt的元对象系统
概述
- QObject类是所有使用元对象系统的类的基类
- 必须在一个类的开头部分插入宏Q_OBJECT,才可以使用元对象系统的特性。当MOC发现类中定义了Q_OBJECT宏时,会为其生成相应的C++源文件
- 元对象编译器(Meta-Object Compiler,MOC)是一个预处理器,先将Qt的特性程序转换为标准C++程序,在由标准C++编译器进行编译
Object类
- 元对象(meta object):每个QObject及其子类的实例都有一个元对象(静态变量
staticMetaObject
)。函数metaObject()
可以返回它的指针。 - 类型信息:
QObject
的inherits()
函数可以判断继承关系。 - 动态翻译:函数
tr()
返回一个字符串的翻译版本。 - 对象树:表示对象间从属关系的树状结构。
QObject
提供了parent()
、children()
、findChildren()
等函数。对象树中的某个对象被删除时,它的子对象也将被删除。 - 信号和槽:对象间的通信机制。
- 属性系统:可以使用宏
Q_PROPERTY
定义属性,Q0bject
的setProperty
会设置属 性的值或定义动态属性;property函数会返回属性的值。
QMetaObject类
- 元对象是对类的描述,包含类信息、方法、属性等元数据。
QObject
和QMetaObject
提供了一些函数接口,可以获取运行时类型信息,类似标准C++中的RTTI(run time type information)
属性系统
在OObject的子类中可以通过Q_PROPERTY宏定义属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton *button = new QPushButton;
QObject *object = button;
bool isFlat = object->property("flatee").toBool();
qDebug()<<isFlat; //类不存在,无法打印
object->setProperty("flatee", true); //setProperty可以在运行时为类定义一个新属性,称之为动态属性
isFlat = object->property("flatee").toBool();
qDebug()<<isFlat;
const QMetaObject *meta = object->metaObject(); //QMetaProperty是属性元数据类型
int index = meta->indexOfProperty("down");
QMetaProperty prop = meta ->property(index);
bool res = prop.isWritable();
qDebug()<<" down(QPushButton) isWritable?: "<<res;
}
信号与槽
信号与槽是元对象系统支持的,对象间通信所采取的机制。
connect
函数的使用
1
2
3
4
5
6
7
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnetionType = Qt::AutoConnection)
//如果信号与槽函数带有参数,需要注明参数类型
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int)));
QMetaObject::Connetion QObject:connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &member, Qt::ConnetionType = Qt::AutoConnection)
//对于信号或槽函数名称是唯一的,不存在歧义的情况下可以省略参数
connect(lineEdit, &QLineEdit::textChanged, this, &widget::on_textChanged);
如果信号和槽函数都存在重载的情况,则需要使用qOverload<参数类型>
进行指定:
1
2
3
4
5
void do_click(bool checked);
void do_click();
connect(ui->checkBox, &QCheckBox::clicked, this,qOverload<bool>(&Widget::do_click));
connect(ui->checkBox, &QCheckBox::clicked, this,qOverload<>(&Widget::do_click));
Qt::ConnectionType
表示了信号与槽之间的关联方式
Qt::AutoConnection
(缺省值):自动确定关联方式
Qt::DirectConnection
:信号被发射时,槽立即执行,槽函数与信号在同一线程
Qt::DirectConnection
:事件循环回到接收者线程后执行槽,槽与信号在不同线程
Qt::BlockingQueueConnection
:与Qt:QueuedConnection
相似,信号线程会被阻塞直到槽执行完毕。当槽函数与信号在同一线程,会造成死锁。
上面的形式都是静态函数版本,无法获得对象本身的this指针。还有成员函数的版本:
this->connection(spinNum, SIGNAL(valueChanged(int)),SLOT(updateStatus(int)));
disconnect()
函数的使用
- 解除与一个sender所有signal的连接:
1
2
disconnect(myObject, nullptr, nullptr, nullptr); //静态函数
myObject->disconnect(); //成员函数
- 解除与一个特定信号的所有连接:
1
2
disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr); //静态函数
myObject->disconnect(SIGNAL(mySignal())); //成员函数
- 解除与一个特定receiver的所有连接:
1
2
disconnect(myObject, nullptr, myReceiver, nullptr); //静态函数
myObject->disconnect(myReceiver); //成员函数
- 解除一对特定的信号和槽的连接:
1
disconnect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText);
sender
函数
在槽函数里,使用QObject::sender()
可以获取信号发射者的指针
1
QSpinBox *spinbox = qobject_cast<QSpinBox*>(sender());
自定义信号及其使用
信号函数必须无返回值,但可以有输入参数;信号函数无需实现,只需在某些条件下发射信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class QPerson:public QObject
{
Q_OBJECT
private:
int m_age = 10;
public:
void incAge();
signals:
void ageChanged(int value);
}
void QPerson::incAge() {
m_age++;
emit ageChanged(m_age); //发射信号
}
对象树
Q0bject
以对象树的形式组织自己,其构造函数里有一个parent
参数。当用另一个对象作为父对象创建一个QObject
时,它会被添加到父对象的children()
列表中,而当父对象被删除时是时,它会被删除。这种方法非常适合GUI对象的需求。例如,QShortcut
(键盘快捷键)是相关窗口的子对象,因此当用户关闭该窗口时,快捷键也会被删除。
children
函数
1
2
3
4
5
//返回对象的子对象列表
const QObjectList &QOject::children()
//函数的返回类型是QObject类型指针列表
typedef QList<QObject*> QObjectList;
例如,修改所有按钮的名称:
1
2
3
4
5
6
7
8
9
10
11
12
QObjectList objList = ui->groupBox_Btns->children();
for(int i = 0; i < objList.size(); i++)
{
const QMetaObject *meta = objList.at(i)->metaObject();
QString className = QString(meta->className());
if(className == "QPushButton")
{
QPushButton *btn = qobject_cast<QPushButton*>(objList.at(i));
QString str-btn->text();
btn->setText(str+"*");
}
}
findChild
函数
返回此对象的一个具有给定名称的子对象,该子对象可以转换为类型T,如果没有该对象,则返回nullptr。
1
2
3
4
5
6
template <typename T> T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively)
const QPushButton *button = parentWidget->findChild<QPushButton*>("button1");
//返回parentWidget的一个子按钮QPushButton,名为“button1”
//即使这个按钮不是父元素的直接元素
省略name
将匹配所有对象。搜索是递归执行的,除非options指定为FindDirectChildrenOnly
findChildren
函数
返回此对象的所有具有给定名称的子对象,这些子对象可以转换为类型T,如果没有此类对象,则返回一个空列表。省略name
参数将匹配所有对象的名称。搜索是递归执行的,除非options
指定了FindDirectChildrenOnly
选项。
1
QList<QWidget*> widget = parentWidget.findChildren<QWidget*>("widgetname");
元对象系统功能测试示例
Qt的元对象系统(Meta-Object System)是Qt编程的基础,它对标准C++语言进行了扩展,支持信号与槽、属性等特性。本示例基于QObject
自定义了一个类TPerson
,演示元对象系统一些特性的使用,包括定义类信息,定义属性,定义动态属性,自定义信号等。