信号与槽
1、QT 信号槽功能由QObject提供,实现基于Qt 元对象系统,其文档描述为:
Signals and slots are made possible by Qt’s meta-object system
2、QObject 类为使用信号槽机制的基类,子类在private 中定义Q_OBJECT宏
3、元对象编译器(MOC)在预编译阶段解析定义有Q_OBJECT宏的源文件,并生成moc_xxx.cpp文件,该文件中包含信号与槽相关信息(名称、信号连接等)
QT文档描述:
The meta-object system is based on three things:
The QObject class provides a base class for objects that can take advantage of the meta-object system.
The Q_OBJECT macro inside the private section of the class declaration is used to enable meta-object features, such as dynamic properties, signals, and slots.
The Meta-Object Compiler (moc) supplies each QObject subclass with the necessary code to implement meta-object features.
The moc tool reads a C++ source file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces another C++ source file which contains the meta-object code for each of those classes. This generated source file is either #include’d into the class’s source file or, more usually, compiled and linked with the class’s implementation.
文章目录
前言
一、Q_OBJECT
源代码定义在qobjectdefs.h 中如下(Qt6.0.2):
/* qmake ignore 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, "")
1、定义静态元对象 QMetaObject
2、获取QMetaObject 的虚函数
3、qt_metacall 元对象调用
4、qt_metacast :根据签名得到相关结构的指针
5、虚函数:
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
MOC在生成的moc_xxx.cpp文件中实现 ,代码如下:
void Worker::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<Worker *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->resultReady((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 1: _t->sig_realAlgMsg((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 2: _t->doWork((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 3: _t->slot_checkRealAlgMsg(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Worker::*)(QString );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::resultReady)) {
*result = 0;
return;
}
}
{
using _t = void (Worker::*)(int , QString );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::sig_realAlgMsg)) {
*result = 1;
return;
}
}
}
}
QT_INIT_METAOBJECT const QMetaObject Worker::staticMetaObject = { {
&QObject::staticMetaObject,
qt_meta_stringdata_Worker.data,
qt_meta_data_Worker,
qt_static_metacall,
nullptr,
nullptr
} };
const QMetaObject *Worker::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *Worker::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_Worker.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
int Worker::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 4)
qt_static_metacall(this, _c, _id, _a);
_id -= 4;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 4)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 4;
}
return _id;
}
二、MOC
MOC:Meta-Object Compiler,“元对象编译器”,预编译时处理带有Q_OBJECT源文件,生成moc_xxx.cpp
生成的moc_xxx.cpp文件可以再cpp中#include 的方式使用,如移植Qt属性设置代码如下:
QT_END_NAMESPACE
#include "moc_qteditorfactory.cpp"
#include "qteditorfactory.moc"
1.QMetaObject
QT 文档描述如下:
A single QMetaObject instance is created for each QObject subclass that is used in an application, and this instance stores all the meta-information for the QObject subclass
翻译:
为应用程序中使用的每个QObject子类创建一个QMetaObject实例,并且该实例存储QObject子类的所有元信息。
className() returns the name of a class.
superClass() returns the superclass’s meta-object.
method() and methodCount() provide information about a class’s meta-methods (signals, slots and other invokable member functions).
enumerator() and enumeratorCount() and provide information about a class’s enumerators.
propertyCount() and property() provide information about a class’s properties.
constructor() and constructorCount() provide information about a class’s meta-constructors.
翻译:
className()返回类的名称。
superClass()返回父类的元对象。
method()和methodCount()提供有关类的元方法(信号,插槽和其他可调用成员函数)的信息。
enumerator()和enumeratorCount()并提供有关类的枚举数的信息。
propertyCount()和property()提供有关类的属性的信息。
Constructor()和ConstructorCount()提供有关类的元构造函数的信息。
2.Moc_xxx.cpp
1、qt_meta_data元数据
qt_meta_data元数据代码如下(示例):
static const uint qt_meta_data_Worker[] = {
// content:
8, // revision 生成代码的moc版本号
0, // classname 类名索引
0, 0, // classinfo 类信息索引
4, 14, // methods 类中信号与槽数目
0, 0, // properties 属性位置信息
0, 0, // enums/sets 枚举位置信息
0, 0, // constructors 构造函数位置信息
0, // flags
2, // signalCount 信号数量
// signals: name, argc, parameters, tag, flags
1, 1, 34, 2, 0x06 /* Public */,
4, 2, 37, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
5, 2, 42, 2, 0x0a /* Public */,
8, 0, 47, 2, 0x0a /* Public */,
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::Int, QMetaType::QString, 2, 2,
// slots: parameters
QMetaType::Void, QMetaType::QString, QMetaType::QString, 6, 7,
QMetaType::Void,
0 // eod
};
3、 signals 信号
moc 处理源文件时将信号函数在moc_xxx.cpp中实现示例如下:
// SIGNAL 0
void Worker::resultReady(QString _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void Worker::sig_realAlgMsg(int _t1, QString _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
信号声明:
4、 slots 槽
slots 标记槽函数, 在moc_xxx.cpp中有槽函数参数信息,示例如下:
// slots: name, argc, parameters, tag, flags
5, 2, 42, 2, 0x0a /* Public */,
8, 0, 47, 2, 0x0a /* Public */,
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210519172411972.png#pic_center
宏slots 前须有 private 、public 、protected修饰,否则编译报错
5、 信号连接
QObject 定义了信号连接函数,根据参数不同,有不同定义,示例如下:
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type)
{
if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
sender ? sender->metaObject()->className() : "(nullptr)",
(signal && *signal) ? signal + 1 : "(nullptr)",
receiver ? receiver->metaObject()->className() : "(nullptr)",
(method && *method) ? method + 1 : "(nullptr)");
return QMetaObject::Connection(nullptr);
}
QByteArray tmp_signal_name;
if (!check_signal_macro(sender, signal, "connect", "bind"))
return QMetaObject::Connection(nullptr);
const QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal;
++signal; // skip code
QArgumentTypeArray signalTypes;
Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
QByteArray signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
int signal_index = QMetaObjectPrivate::indexOfSignalRelative(
&smeta, signalName, signalTypes.size(), signalTypes.constData());
if (signal_index < 0) {
// check for normalized signatures
tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
signal = tmp_signal_name.constData() + 1;
signalTypes.clear();
signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
smeta = sender->metaObject();
signal_index = QMetaObjectPrivate::indexOfSignalRelative(
&smeta, signalName, signalTypes.size(), signalTypes.constData());
}
if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect");
err_info_about_objects("connect", sender, receiver);
return QMetaObject::Connection(nullptr);
}
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
signal_index += QMetaObjectPrivate::signalOffset(smeta);
QByteArray tmp_method_name;
int membcode = extract_code(method);
if (!check_method_code(membcode, receiver, method, "connect"))
return QMetaObject::Connection(nullptr);
const char *method_arg = method;
++method; // skip code
QArgumentTypeArray methodTypes;
QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
const QMetaObject *rmeta = receiver->metaObject();
int method_index_relative = -1;
Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
switch (membcode) {
case QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
&rmeta, methodName, methodTypes.size(), methodTypes.constData());
break;
case QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
&rmeta, methodName, methodTypes.size(), methodTypes.constData());
break;
}
if (method_index_relative < 0) {
// check for normalized methods
tmp_method_name = QMetaObject::normalizedSignature(method);
method = tmp_method_name.constData();
methodTypes.clear();
methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
// rmeta may have been modified above
rmeta = receiver->metaObject();
switch (membcode) {
case QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
&rmeta, methodName, methodTypes.size(), methodTypes.constData());
break;
case QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
&rmeta, methodName, methodTypes.size(), methodTypes.constData());
break;
}
}
if (method_index_relative < 0) {
err_method_notfound(receiver, method_arg, "connect");
err_info_about_objects("connect", sender, receiver);
return QMetaObject::Connection(nullptr);
}
if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
methodTypes.size(), methodTypes.constData())) {
qCWarning(lcConnect,
"QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s",
sender->metaObject()->className(), signal, receiver->metaObject()->className(),
method);
return QMetaObject::Connection(nullptr);
}
int *types = nullptr;
if ((type == Qt::QueuedConnection)
&& !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
return QMetaObject::Connection(nullptr);
}
#ifndef QT_NO_DEBUG
QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
check_and_warn_compat(smeta, smethod, rmeta, rmethod);
#endif
QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
return handle;
}
1、参数合法性判断
2、check_signal_macro 检测信号定义
static bool check_signal_macro(const QObject *sender, const char *signal,
const char *func, const char *op)
{
int sigcode = extract_code(signal);
if (sigcode != QSIGNAL_CODE) {
if (sigcode == QSLOT_CODE)
qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
sender->metaObject()->className(), signal + 1);
else
qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
sender->metaObject()->className(), signal);
return false;
}
return true;
}
static int extract_code(const char *member)
{
// extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
return (((int)(*member) - '0') & 0x3);
}
3、获取信号索引
int signal_index = QMetaObjectPrivate::indexOfSignalRelative
4、获取槽索引 QMetaObjectPrivate::indexOfSignalRelative
5、检查连接参数 QMetaObjectPrivate::checkConnectArgs
6、生成连接
QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
return handle;
class Q_CORE_EXPORT QMetaObject::Connection {
void *d_ptr; //QObjectPrivate::Connection*
explicit Connection(void *data) : d_ptr(data) { }
friend class QObject;
friend class QObjectPrivate;
friend struct QMetaObject;
bool isConnected_helper() const;
public:
~Connection();
Connection();
Connection(const Connection &other);
Connection &operator=(const Connection &other);
#ifdef Q_QDOC
operator bool() const;
#else
// still using the restricted bool trick here, in order to support
// code using copy-init (e.g. `bool ok = connect(...)`)
typedef void *Connection::*RestrictedBool;
operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : nullptr; }
#endif
Connection(Connection &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Connection)
void swap(Connection &other) noexcept { qSwap(d_ptr, other.d_ptr); }
};
Connect 结构定义 QObjectPrivate,默认队列连接 因为
ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
struct Connection : public ConnectionOrSignalVector
{
// linked list of connections connected to slots in this object, next is in base class
Connection **prev;
// linked list of connections connected to signals in this object
QAtomicPointer<Connection> nextConnectionList;
Connection *prevConnectionList;
QObject *sender;
QAtomicPointer<QObject> receiver;
QAtomicPointer<QThreadData> receiverThreadData;
union {
StaticMetaCallFunction callFunction;
QtPrivate::QSlotObjectBase *slotObj;
};
QAtomicPointer<const int> argumentTypes;
QAtomicInt ref_;
uint id = 0;
ushort method_offset;
ushort method_relative;
signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
ushort isSlotObject : 1;
ushort ownArgumentTypes : 1;
ushort isSingleShot : 1;
Connection() : ref_(2), ownArgumentTypes(true) {
//ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
}
~Connection();
int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
void ref() { ref_.ref(); }
void freeSlotObject()
{
if (isSlotObject) {
slotObj->destroyIfLastRef();
isSlotObject = false;
}
}
void deref()
{
if (!ref_.deref()) {
Q_ASSERT(!receiver.loadRelaxed());
Q_ASSERT(!isSlotObject);
delete this;
}
}
};
// ConnectionList is a singly-linked list
struct ConnectionList {
QAtomicPointer<Connection> first;
QAtomicPointer<Connection> last;
};
struct ConnectionOrSignalVector {
union {
// linked list of orphaned connections that need cleaning up
ConnectionOrSignalVector *nextInOrphanList;
// linked list of connections connected to slots in this object
Connection *next;
};
static SignalVector *asSignalVector(ConnectionOrSignalVector *c)
{
if (reinterpret_cast<quintptr>(c) & 1)
return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
return nullptr;
}
static Connection *fromSignalVector(SignalVector *v) {
return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
}
};
6、 信号触发
moc_xxx.cpp 中信号函数:
// SIGNAL 0
void Worker::resultReady(QString _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
信号触发实现:
static void activate(QObject *sender, int signal_index, void **argv);
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
doActivate<true>(sender, signal_index, argv);
else
doActivate<false>(sender, signal_index, argv);
}
template <bool callbacks_enabled>
void doActivate(QObject *sender, int signal_index, void **argv)
{
QObjectPrivate *sp = QObjectPrivate::get(sender);
if (sp->blockSig)
return;
Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
if (sp->isDeclarativeSignalConnected(signal_index)
&& QAbstractDeclarativeData::signalEmitted) {
Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
signal_index, argv);
}
const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
void *empty_argv[] = { nullptr };
if (!argv)
argv = empty_argv;
if (!sp->maybeSignalConnected(signal_index)) {
// The possible declarative connection is done, and nothing else is connected
if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
signal_spy_set->signal_begin_callback(sender, signal_index, argv);
if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
signal_spy_set->signal_end_callback(sender, signal_index);
return;
}
if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
signal_spy_set->signal_begin_callback(sender, signal_index, argv);
bool senderDeleted = false;
{
Q_ASSERT(sp->connections.loadAcquire());
QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
const QObjectPrivate::ConnectionList *list;
if (signal_index < signalVector->count())
list = &signalVector->at(signal_index);
else
list = &signalVector->at(-1);
Qt::HANDLE currentThreadId = QThread::currentThreadId();
bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
// We need to check against the highest connection id to ensure that signals added
// during the signal emission are not emitted in this emission.
uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
do {
QObjectPrivate::Connection *c = list->first.loadRelaxed();
if (!c)
continue;
do {
QObject * const receiver = c->receiver.loadRelaxed();
if (!receiver)
continue;
QThreadData *td = c->receiverThreadData.loadRelaxed();
if (!td)
continue;
bool receiverInSameThread;
if (inSenderThread) {
receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
} else {
// need to lock before reading the threadId, because moveToThread() could interfere
QMutexLocker lock(signalSlotLock(receiver));
receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
}
// determine if this connection should be sent immediately or
// put into the event queue
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_index, c, argv);
continue;
#if QT_CONFIG(thread)
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
if (receiverInSameThread) {
qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
"Sender is %s(%p), receiver is %s(%p)",
sender->metaObject()->className(), sender,
receiver->metaObject()->className(), receiver);
}
if (c->isSingleShot && !QObjectPrivate::disconnect(c))
continue;
QSemaphore semaphore;
{
QBasicMutexLocker locker(signalSlotLock(receiver));
if (!c->isSingleShot && !c->receiver.loadAcquire())
continue;
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
sender, signal_index, argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
}
semaphore.acquire();
continue;
#endif
}
if (c->isSingleShot && !QObjectPrivate::disconnect(c))
continue;
QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
if (c->isSlotObject) {
c->slotObj->ref();
struct Deleter {
void operator()(QtPrivate::QSlotObjectBase *slot) const {
if (slot) slot->destroyIfLastRef();
}
};
const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};
{
Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());
obj->call(receiver, argv);
}
} else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
const int method_relative = c->method_relative;
const auto callFunction = c->callFunction;
const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
}
if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
signal_spy_set->slot_end_callback(receiver, methodIndex);
} else {
const int method = c->method_relative + c->method_offset;
if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
signal_spy_set->slot_begin_callback(receiver, method, argv);
}
{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
}
if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
signal_spy_set->slot_end_callback(receiver, method);
}
} while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
} while (list != &signalVector->at(-1) &&
//start over for all signals;
((list = &signalVector->at(-1)), true));
if (connections->currentConnectionId.loadRelaxed() == 0)
senderDeleted = true;
}
if (!senderDeleted) {
sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
signal_spy_set->signal_end_callback(sender, signal_index);
}
}
7、 槽响应
qt_static_metacall实现槽函数调用:
示例代码如下:
void Worker::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<Worker *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->resultReady((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 1: _t->sig_realAlgMsg((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 2: _t->doWork((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 3: _t->slot_checkRealAlgMsg(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Worker::*)(QString );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::resultReady)) {
*result = 0;
return;
}
}
{
using _t = void (Worker::*)(int , QString );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::sig_realAlgMsg)) {
*result = 1;
return;
}
}
}
}
总结
参考:
https://blog.51cto.com/u_9291927/2070348
https://blog.csdn.net/chengkeke366/article/details/109500723
https://blog.csdn.net/ddllrrbb/article/details/88374350?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control