我是靠谱客的博主 乐观心情,最近开发中收集的这篇文章主要介绍QT之信号与槽,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • 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)提供的,元对象系统主要基于以下三点:

  1. QObject:只有该类及该类的派生类才能使用元对象系统。
  2. 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, "")
  1. 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) // ""

    },
    "TextFinderon_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之信号与槽所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部