概述
文章目录
- meta-object system
QT的信号与槽机制主要是为了实现不同部件之间的信息交互,即一个部件状态发生了变化,希望相关的部件能获知该变化并做出响应。那么前者可在状态变化时发射一个信号,则与该信号连接了的槽函数都会被按连接顺序依次调用。与回调(callback)机制不同的是,信号与槽机制实现了发布者和订阅者的解耦合,即发布者不知道也无需知道谁会捕获发射的信号,订阅者亦然。
尝试搞明白QT的信号与槽机制底层是怎么实现的,但是感觉只是触及到了一些比较核心的概念,完整的逻辑还是没能完全搞明白。 主要欠缺的部分是信号和槽是怎么联系起来的,文中做了些猜想。虽不完整,还是记录一下,以便后续能继续探索。
meta-object system
Qt’s meta-object system provides the signals and slots mechanism for inter-object communication, run-time type information, and the dynamic property system.
QT的信号与槽机制是由其元对象系统(meta-object system)提供的,元对象系统主要基于以下三点:
- QObject:只有该类及该类的派生类才能使用元对象系统。
- Q_OBJECT:在QObject类及其派生类中使用元对象系统,必须在类的开始位置调用Q_OBJECT宏,该宏会提供一系列的元对象系统相关的声明(QMetaObject),以支持信号与槽机制、运行时类型信息和动态参数系统。
例如定义如下类:
#ifndef TEXTFINDER_H
#define TEXTFINDER_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class TextFinder; }
QT_END_NAMESPACE
class TextFinder : public QWidget
{
Q_OBJECT
public:
TextFinder(QWidget *parent = nullptr);
void metaInfo();
~TextFinder();
private slots:
void on_findButton_clicked();
private:
Ui::TextFinder *ui;
void loadTextFile();
};
#endif // TEXTFINDER_H
其中Q_OBJECT会被扩展为如下代码:
#define Q_OBJECT
public:
QT_WARNING_PUSH
Q_OBJECT_NO_OVERRIDE_WARNING
static const QMetaObject staticMetaObject;
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
QT_TR_FUNCTIONS
private:
Q_OBJECT_NO_ATTRIBUTES_WARNING
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
QT_WARNING_POP
struct QPrivateSignal {};
QT_ANNOTATE_CLASS(qt_qobject, "")
- moc(Meta-Object Compiler):QT提供的元对象编译工具,该工具识别到类中的Q_OBJECT宏后,会为上面Q_OBJECT宏展开的声明提供定义,文件名为moc_<classname>.h,本例生成的改文件内容为:
/****************************************************************************
** Meta object code from reading C++ file 'textfinder.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.9.9)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../TextFinder/textfinder.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'textfinder.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.9.9. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_TextFinder_t {
QByteArrayData data[3];
char stringdata0[34];
};
#define QT_MOC_LITERAL(idx, ofs, len)
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len,
qptrdiff(offsetof(qt_meta_stringdata_TextFinder_t, stringdata0) + ofs
- idx * sizeof(QByteArrayData))
)
static const qt_meta_stringdata_TextFinder_t qt_meta_stringdata_TextFinder = {
{
QT_MOC_LITERAL(0, 0, 10), // "TextFinder"
QT_MOC_LITERAL(1, 11, 21), // "on_findButton_clicked"
QT_MOC_LITERAL(2, 33, 0) // ""
},
"TextFinder on_findButton_clicked "
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_TextFinder[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: name, argc, parameters, tag, flags
1, 0, 19, 2, 0x08 /* Private */,
// slots: parameters
QMetaType::Void,
0 // eod
};
void TextFinder::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
TextFinder *_t = static_cast<TextFinder *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->on_findButton_clicked(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObject TextFinder::staticMetaObject = {
{ &QWidget::staticMetaObject, qt_meta_stringdata_TextFinder.data,
qt_meta_data_TextFinder, qt_static_metacall, nullptr, nullptr}
};
const QMetaObject *TextFinder::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *TextFinder::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_TextFinder.stringdata0))
return static_cast<void*>(this);
return QWidget::qt_metacast(_clname);
}
int TextFinder::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 1)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 1;
}
return _id;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
可以看到moc
对Q_OBJECT的声明提供了函数定义,其中的函数功能分别为:
qt_static_metacall
:类的私有函数,真正调用槽函数的位置,其参数_id
决定了调用哪个槽函数。我猜想将信号与槽进行connect的时候,会维护一个键值对,分别是整数表示的信号与槽的index。qt_metacall
:公有函数,在这里会调用qt_static_metacall
。metaObject
: 返回一个包含该类元信息的元对象的指针,即TextFinder::staticMetaObject
,该对象也是moc构造的。
最后
以上就是乐观心情为你收集整理的QT之信号与槽的全部内容,希望文章能够帮你解决QT之信号与槽所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复