Qt——信号与槽的原理

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值