QT元对象系统
QT元对象系统的三个重要组成包括:
1)QObject类(所有使用元对象系统的基类)
2)Q_OBJECT(所在类可以使用元对象特性)
3)MOC(meta-object-compiler,元对象编译器,预处理包含Q_OBJECT宏的类)
整体的编译过程
首先进行MOC预处理,Q_OBJECT宏将展开和自动生成一些变量定义、函数声明等代码,同时生成moc_xxx.cpp,之后进行普通编译。
信号与槽的预处理:看成普通函数
1)在MOC预处理过程中,Q_OBJECT将展开,类中定义的信号和槽也被处理。
2)处理后会将信号与槽都作为可回调的函数,根据id调用,函数及其id的定义在Q_OBJECT展开的函数qt_static_metacall中,如实例1
3)其区别是在不同的关键字(signals,slots)声明下,信号的实现由moc完成,如实例2,而槽函数的实现需要自己完成。
信号与槽的关联:构建Connection对象
1)connect函数构造了一个Connection对象,将接发对象、函数(信号槽)的id、连接方式等保存在发送者内存,如实例3。
2)而发送者将内存中的Connection对象保存在QObjectConnectionListVector中,QObjectConnectionListVector是个数组,通过信号id索引。
3)一个信号可以连接多个槽,则信号id索引的内容是数组某个位置的ConnectionList。
信号的触发与槽的执行:执行函数回调
1)执行emit,则相当于调用QMetaObject::activate函数,此时通过信号id,获得ConnectionList。
2)对于直连的信号槽,会直接执行槽函数id对应的函数;
3)对于队列连接的槽函数,将通过QMetaObject::queued_activate,抛出QMetaCallEvent事件,把Connection扔到接受者所在线程,在接受者所在线程的事件循环中执行,如实例4。
参考
1、https://www.cnblogs.com/swarmbees/p/10816139.html
实例
实例1
void MasterConsole::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<MasterConsole *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->publishOrder((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 1: _t->toBuilder(); break;
case 2: _t->toDeleter(); break;
case 3: _t->on_btnTestStartDistribution_clicked(); break;
default: ;
}
//...
}
实例2
// SIGNAL 1
void MasterConsole::toBuilder()
{
QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}
实例3
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
c->sender = s; //发送者
c->signal_index = signal_index; //信号索引
c->receiver = r; //接收者
c->method_relative = method_index; //槽函数索引
c->method_offset = method_offset; //槽函数偏移 主要是区别于多个信号
c->connectionType = type; //连接类型
c->isSlotObject = false; //是否是槽对象 默认是true
c->argumentTypes.store(types); //参数类型
c->nextConnectionList = 0; //指向下个连接对象
c->callFunction = callFunction; //静态回调函数,也就是qt_static_metacall
QObjectPrivate::get(s)->addConnection(signal_index, c.data());
实例4
void QMetaObject::activate(QObject *sender, int signalOffset ......)
{
. . . . . .
//发送方和接收方是否在同一个线程中
const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;
//决定连接立刻发送还是加入事件队列
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection))
{
queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
continue;
} else if
//...
}
static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, QMutexLocker &locker)
{
...
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
sender, signal, nargs, types, args);
//post事件到接收者所属线程的QThreadData::postEventList队列中
QCoreApplication::postEvent(c->receiver, ev);
...
}
实例5:一个简单的moc_xxx.cpp文件
/****************************************************************************
** Meta object code from reading C++ file 'masterconsole.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.6)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../SandTable_MasterConsole/masterconsole.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'masterconsole.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.6. 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_MasterConsole_t {
QByteArrayData data[12];
char stringdata0[235];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_MasterConsole_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_MasterConsole_t qt_meta_stringdata_MasterConsole = {
{
QT_MOC_LITERAL(0, 0, 13), // "MasterConsole"
QT_MOC_LITERAL(1, 14, 12), // "publishOrder"
QT_MOC_LITERAL(2, 27, 0), // ""
QT_MOC_LITERAL(3, 28, 2), // "id"
QT_MOC_LITERAL(4, 31, 5), // "order"
QT_MOC_LITERAL(5, 37, 9), // "toBuilder"
QT_MOC_LITERAL(6, 47, 9), // "toDeleter"
QT_MOC_LITERAL(7, 57, 35), // "on_btnTestStartDistribution_c..."
QT_MOC_LITERAL(8, 93, 35), // "on_btnTestCloseDistribution_c..."
QT_MOC_LITERAL(9, 129, 33), // "on_btnTestStartManagement_cli..."
QT_MOC_LITERAL(10, 163, 33), // "on_btnTestCloseManagement_cli..."
QT_MOC_LITERAL(11, 197, 37) // "on_btnTestFunction_singleCar1..."
},
"MasterConsole\0publishOrder\0\0id\0order\0"
"toBuilder\0toDeleter\0"
"on_btnTestStartDistribution_clicked\0"
"on_btnTestCloseDistribution_clicked\0"
"on_btnTestStartManagement_clicked\0"
"on_btnTestCloseManagement_clicked\0"
"on_btnTestFunction_singleCar1_clicked"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_MasterConsole[] = {
// content:
8, // revision
0, // classname
0, 0, // classinfo
8, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// signals: name, argc, parameters, tag, flags
1, 2, 54, 2, 0x06 /* Public */,
5, 0, 59, 2, 0x06 /* Public */,
6, 0, 60, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
7, 0, 61, 2, 0x08 /* Private */,
8, 0, 62, 2, 0x08 /* Private */,
9, 0, 63, 2, 0x08 /* Private */,
10, 0, 64, 2, 0x08 /* Private */,
11, 0, 65, 2, 0x08 /* Private */,
// signals: parameters
QMetaType::Void, QMetaType::Int, QMetaType::QString, 3, 4,
QMetaType::Void,
QMetaType::Void,
// slots: parameters
QMetaType::Void,
QMetaType::Void,
QMetaType::Void,
QMetaType::Void,
QMetaType::Void,
0 // eod
};
void MasterConsole::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<MasterConsole *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->publishOrder((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
case 1: _t->toBuilder(); break;
case 2: _t->toDeleter(); break;
case 3: _t->on_btnTestStartDistribution_clicked(); break;
case 4: _t->on_btnTestCloseDistribution_clicked(); break;
case 5: _t->on_btnTestStartManagement_clicked(); break;
case 6: _t->on_btnTestCloseManagement_clicked(); break;
case 7: _t->on_btnTestFunction_singleCar1_clicked(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (MasterConsole::*)(int , QString );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MasterConsole::publishOrder)) {
*result = 0;
return;
}
}
{
using _t = void (MasterConsole::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MasterConsole::toBuilder)) {
*result = 1;
return;
}
}
{
using _t = void (MasterConsole::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MasterConsole::toDeleter)) {
*result = 2;
return;
}
}
}
}
QT_INIT_METAOBJECT const QMetaObject MasterConsole::staticMetaObject = { {
&QMainWindow::staticMetaObject,
qt_meta_stringdata_MasterConsole.data,
qt_meta_data_MasterConsole,
qt_static_metacall,
nullptr,
nullptr
} };
const QMetaObject *MasterConsole::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *MasterConsole::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_MasterConsole.stringdata0))
return static_cast<void*>(this);
return QMainWindow::qt_metacast(_clname);
}
int MasterConsole::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QMainWindow::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 8)
qt_static_metacall(this, _c, _id, _a);
_id -= 8;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 8)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 8;
}
return _id;
}
// SIGNAL 0
void MasterConsole::publishOrder(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, 0, _a);
}
// SIGNAL 1
void MasterConsole::toBuilder()
{
QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}
// SIGNAL 2
void MasterConsole::toDeleter()
{
QMetaObject::activate(this, &staticMetaObject, 2, nullptr);
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE