• 信号与槽的连接方式


    QT通过connect关联信号和槽函数

    一、槽函数的执行是同步还是异步

    在同一个线程中,Qt信号槽的执行是同步的。当一个信号被发射时,槽函数会立即被调用,而不是被放入事件队列中。这是因为在同一个线程中,事件循环和槽函数都是在同一个线程中执行的,所以槽函数的执行不会阻塞信号的发射者或其他槽函数的执行。

    在不同的线程中,Qt信号槽的执行是异步的。当一个信号被发射时,槽函数不会立即被调用,而是被放入接收对象所在线程的事件队列中,等待事件循环处理。由于事件循环和槽函数在不同的线程中执行,因此槽函数的执行可能会被其他线程的操作所阻塞,这也就是为什么Qt建议在槽函数中避免执行耗时的操作的原因。

    需要注意的是,如果在槽函数中执行的操作比较耗时,会导致当前线程被阻塞,从而影响应用程序的响应性能。因此,在编写槽函数时,应该尽量避免执行耗时的操作,或者将这些操作放在单独的线程中执行。

    二、connect的Qt5以前的写法

    Qt5以前的connect有以下几种:

    1. bool connect(const QObject *, const char *,
    2. const QObject *, const char *,
    3. Qt::ConnectionType);
    4. bool connect(const QObject *, const QMetaMethod &,
    5. const QObject *, const QMetaMethod &,
    6. Qt::ConnectionType);
    7. bool connect(const QObject *, const char *,
    8. const char *,
    9. Qt::ConnectionType) const

    Qt4的SIGNAL和SLOT两个宏,实际是将其参数转换成相应的字符串。在编译之前,Qt的moc工具从源代码中提取出所需要的元数据,形成一张由使用了signals和slots修饰的所有函数组成的字符串表。connect函数将与信号关联起来的槽的字符串,同这张字符串表中的信息进行比较匹配,也就能够在发出信号时知道需要调用哪个槽函数。

    注意,不能将全局函数或者 Lambda 表达式传入connect()。使用字符串导致了Qt4有以下缺点:一旦出现连接不成功的情况,Qt 4 是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。

    1. connect(obj1, SIGNAL(fun1(param1, param2,...)), obj2, SLOT(fun2(param1,...)));
    2. // 举个例子
    3. QLabel *label = new QLabel;
    4. QScrollBar *scrollBar = new QScrollBar;
    5. QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
    6. label, SLOT(setNum(int)));

    优点:对所有控件都适用。

    缺点:书写繁琐,槽函数必须在slot标签下。在程序编译阶段,程序会将函数以字符串的形式进行链接,程序不会检查信号/槽函数是否存在,只有在运行期间才会验证是否正确

    三、Qt5的写法

    为了解决Qt4中connect的问题,Qt5写法有以下几种

    1. QMetaObject::Connection connect(const QObject *, const char *,
    2. const QObject *, const char *,
    3. Qt::ConnectionType);
    4. QMetaObject::Connection connect(const QObject *, const QMetaMethod &,
    5. const QObject *, const QMetaMethod &,
    6. Qt::ConnectionType);
    7. QMetaObject::Connection connect(const QObject *, const char *,
    8. const char *,
    9. Qt::ConnectionType) const;
    10. QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
    11. const QObject *, PointerToMemberFunction,
    12. Qt::ConnectionType)
    13. QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
    14. Functor);

    举个例子

    1. QLabel *label = new QLabel;
    2. QLineEdit *lineEdit = new QLineEdit;
    3. QObject::connect(lineEdit, &QLineEdit::textChanged,
    4. label, &QLabel::setText);

    优点:书写简便,编译期间就会检查信号与槽是否存在,参数类型检查,Q_OBJECT是否存在,槽函数不在限定必须是slot,可以是普通的函数、类的普通成员函数、lambda函数。

    缺点:函数重载,有可能会造成程序的困扰,不知道该具体链接哪个

    四、connect的Qt::ConnectionType(信号与槽的关联类型)

    Qt文档如下

    翻译过来是这样:

    第5个参数一般不填,为默认值。

      1、Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

      2、Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数和信号发送者在同一线程。效果看上去就像是直接在信号发送位置调用了槽函数,效果上看起来像函数调用,同步执行。

    emit语句后面的代码将在与信号关联的所有槽函数执行完毕后才被执行。

      3、Qt::QueuedConnection:信号发出后,信号会暂时被放到一个消息队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作。

    emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕

      4、Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。而且接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

      5、Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是为了避免重复连接。
     

    五、信号槽的原理

    1. moc查找头文件中的signals,slots,标记出信号和槽。
    2. 将信号槽信息存储到类静态变量staticMetaObject中,并且按声明顺序进行存放,建立索引。
    3. 当发现有connect连接时,将信号槽的索引信息放到一个map中,彼此配对。
    4. 当调用emit时,调用信号函数,并且传递发送信号的对象指针,元对象指针,信号索引,参数列表到active函数
    5. 通过active函数找到在map中找到所有与信号对应的槽索引
    6. 根据槽索引找到槽函数,执行槽函数。
       

    参考:

    QT信号槽实现原理 - 简书

    nno信号与槽的连接方式 - MaxBruce - 博客园c

  • 相关阅读:
    持续集成实战 —— Jenkins自动化测试环境搭建
    Java:Java有多流行,有哪些主要应用程序?
    OpenCV报错:AttributeError: module ‘cv2.cv2‘ has no attribute ‘SIFT_create‘
    ubuntu18.04虚拟机ros1乐动激光雷达LD06/LD19/LD300的使用
    基于reactor设计websocket服务器
    Feign源码解析6:如何集成discoveryClient获取服务列表
    代码随想录训练营第59天|503.下一个更大元素II,42.接雨水
    MySQL(二)SQL分类和语言规范
    Win11策略服务被禁用怎么办?Win11策略服务被禁用的解决方法
    漏刻有时百度地图API实战开发(5)区域限制移动端鬼畜抖动的解决方案
  • 原文地址:https://blog.csdn.net/sinat_31608641/article/details/126695666