欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > Qt 信号与槽的使用详解 - 多种绑定形式、同步异步、Lambda表达式等

Qt 信号与槽的使用详解 - 多种绑定形式、同步异步、Lambda表达式等

2025/7/8 17:18:50 来源:https://blog.csdn.net/qq_38204686/article/details/139702275  浏览:    关键词:Qt 信号与槽的使用详解 - 多种绑定形式、同步异步、Lambda表达式等

Qt 信号与槽的使用详解 - 多种绑定形式、同步异步、Lambda表达式等

  • 引言
  • 一、信号与槽常见的绑定形式
  • 二、信号与槽的连接方式 - 同步异步

引言

在Qt框架中,信号与槽(Signals and Slots)机制是一种强大的通信方式,它允许对象之间进行通信而无需知道彼此的详细实现。这种机制是Qt的核心特性之一,广泛应用于事件处理和对象间的通信,能够大大简化编程的复杂性,提高代码的可维护性和可扩展性。

一、信号与槽常见的绑定形式

使用connect连接信号 (槽函数的参数个数必须小于等于信号函数的参数个数)

    1. connect函数指针 (推荐),例程如下:
      QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
	QLabel *label = new QLabel;QLineEdit *lineEdit = new QLineEdit;QObject::connect(lineEdit, &QLineEdit::textChanged,label,  &QLabel::setText);
	connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::slot_cs);  // slot_cs是一个普通的槽函数

Qt 5中推荐的信号与槽连接语法,支持函数提示 - 函数补全,会在编译时检查到连接错误

    1. Lambda表达式(推荐) - 连接和槽函数的实现写在一切,方便、简洁且直观,例程如下:
      QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
  QByteArray page = ...;QTcpSocket *socket = new QTcpSocket;socket->connectToHost("qt-project.org", 80);QObject::connect(socket, &QTcpSocket::connected, this, [=] () {socket->write("GET " + page + "\r\n");}, Qt::AutoConnection);

lambda表达式(函数)详解:https://blog.csdn.net/LF__plus/article/details/136873469 - 表达式结构、参数解释

还有个类似的QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor),少了接受者。

    1. 标准connect连接(不推荐) - QT4老语法,例程如下:
      QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
  QLabel *label = new QLabel;QScrollBar *scrollBar = new QScrollBar;QObject::connect(scrollBar, SIGNAL(valueChanged(int)),label,  SLOT(setNum(int)));

需要注意,signal和slots参数不能包含任何变量名,只能包含类型。相比connect函数指针的连接方式,不能进行函数补全,由于使用宏将信号和槽函数转换为字符串,如果有问题在运行时候才会报错,编译阶段不检查。
还有一个类似的QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection),使用QMetaMethod作为信号和槽函数,而不是字符串.

    1. 界面上设置
      1)- 右键控件 - 点击转到槽 - 点击相应的信号,自动生成相应的槽函数,默认绑定无需connect
      2)- 在ui设计界面底部,添加信号和槽的对应关系,如下图所示:
      在这里插入图片描述

一般用的不多的知识点:

  1. 将一个信号连接到另一个信号上,当第一个信号发射时,会触发第二个信号
  2. 信号和槽可以重载,使用QOverload 和 QMetaObject::Connection处理重载信号和槽
  3. 一个信号可以连接多个槽,一个槽也能被多个信号连接
  4. 使用disconnect断开信号和槽的连接
  5. 一个信号和一个槽函数和进行多次connect连接,一次触发多次执行… 可以设置连接类型来规避这种情况UniqueConnection
  6. 发送信号不用加emit也行

可参考:

  1. Qt中connect()方法的一些常见用法:https://blog.csdn.net/weixin_42478379/article/details/137682367
  2. QT标准connect连接(QT4老语法):https://zhuanlan.zhihu.com/p/692721646
  3. QT 信号与槽4种绑定形式:https://blog.csdn.net/weixin_42127524/article/details/131189259
  4. 槽函数被执行多次的解决方法及Qt::UniqueConnection作用及和其它连接类型的“与”操作写法:https://blog.csdn.net/danshiming/article/details/123162126
  5. Qt信号槽/使用问题:https://blog.csdn.net/quguanxin/article/details/102843961

二、信号与槽的连接方式 - 同步异步

信号与槽的连接最后有一个枚举参数Qt::ConnectionType type = Qt::AutoConnection,默认自动。此参数主要表示信号是立即发出还是排队等待:

常量
描述
Qt::AutoConnection0(默认) 发送接收在同一线程,则Qt::DirectConnection,否则Qt::QueuedConnection
Qt::DirectConnection1发出信号时会立即槽函数,在信号发出者的线程中执行。
Qt::QueuedConnection2在接受者的事件循环(线程)中调用。- 异步
Qt::BlockingQueuedConnection3Qt::QueuedConnection一样,也在接受者线程中调用,但是发送信号的线程会被阻塞,直到槽函数执行完毕 (防止槽函数和信号线程对某个值的操纵冲突)。 - 同步
Qt::UniqueConnection0x80一个标志,可以与上述连接方式进行组合 保证同一信号和同一槽函数只能连接一次,再次connect连接会失败。
  1. 对于排队连接Qt::QueuedConnection,参数必须是Qt的元对象系统已知的类型,因为Qt需要复制参数以将其存储在幕后事件中。如若是自定义类型,可以使用qRegisterMetaType()注册一下。
  2. 对于Qt::BlockingQueuedConnection,不能用于发送者接受者在同一个线程的情况,会引起死锁。 - (为啥?可参考博客:由Qt::BlockingQueuedConnection引起的关闭Qt主页面而后台仍有进程残留:https://blog.csdn.net/youzai2017/article/details/132746319)
  3. 当Lambda表达式作为槽函数时,记得使用以上推荐的方式,写全参数。如果省略接受者,默认会在发送者的线程中直接执行。- 比如一个线程发出信号,主线程(UI)线程响应修改相关UI,不写接受者是主线程,会冲突报错,因为只有主线程(UI)线程可以修改UI。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com