QT信号槽连接方式

本文详细介绍了QT信号槽的两种连接方式(手动和自动),包括connect()函数的不同用法(如Qt::AutoConnection、DirectConnection等),以及线程同步和异步处理。重点讲解了信号槽在多线程环境下的行为和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.QT信号槽主要分两个连接方式,手动和自动:
1.1 使用 connect() 函数手动连接信号和槽:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
自动:
1.2 使用 lambda 表达式连接信号和槽:
connect(sender, &Sender::signal, ={
receiver->slot();
});
1.3 通过使用 QMetaObject::connectSlotsByName() 函数自动将部件中以 on_ 开头命名的槽函数与其对应的信号相连接。例如,在设计窗口中选择一个按钮,并在属性编辑器中设置其 objectName 属性为 “myButton”,然后定义一个 on_myButton_clicked() 槽函数,该函数将自动连接到该按钮的 clicked() 信号上。
2.connect()函数的五种连接方式,一次连接,终身调用,除非disconnect。

enum ConnectionType {
	AutoConnection,//默认
	DirectConnection,//立即调用
	QueuedConnection,//放在接收者队列
	BlockingQueuedConnection,//与放在接收者队列,同时阻塞发送者
	UniqueConnection =  0x80//标志位,避免重复链接
};

connect()函数原型如下:

[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

2.1 Qt::AutoConnection(默认)
根据 sender 和 receiver 两者所在线程,当信号发出时作出判断。同一线程则 Qt::DirectConnection 连接,否则使用 Qt::QueuedConnection 连接。容易产生误区的点:不是sender的所属线程,而是真正触发了emit 信号的动作线程。

Qt::DirectConnection
无论sender和receiver是否在同一线程,都会立刻调用槽函数,最简单的理解成把一段代码“临时插入”到了运行栈,所以在多线程情况下非常危险,必须做好线程同步。

Qt::QueuedConnection
sender的信号会被压入到接收者的事件循环中,所以不会立即调用。而是等到当接收者对象处理其自身的消息队列时,再针对消息队列中的这个信号进行处理。可以说就是为了开发者解决跨线程通信而设计的。当然你也可以用于同一个线程不同对象,这种相同线程的强行指定队列方式通常都会和GUI的模态窗有关。

Qt::BlockingQueuedConnection
Blocking+QueuedConnection,他的槽函数运行时机与QueuedConnection是一致的。那Blocking的意义是什么?就是阻塞发送者!直到槽函数运行完毕再继续执行。源码上相比QueuedConnection的实现多加了一个等待输入的信号量QSemaphore,所以一旦接收者和发送者在同一线程,那就会发生死锁。

Qt::UniqueConnection
这个其实严格上来说相比上面四种方式并不算新的连接方式,而是用于修饰上面的四种连接方式。他实现的效果就是避免重复连接,因为Qt的信号槽是可以同一个信号和槽函数重复多次连接。这种通常都会是只执行一次就好,那就通过这个标志位进行修饰,达到多次连接(实际上也只是连接了一次)也只调用一次槽函数的效果。用(Qt::ConnectionType|Qt::UniqueConnection)来修饰。

connect(ui->btn_close, &QPushButton::clicked, this, &QWidget::close,Qt::DirectConnection|Qt::UniqueConnection)

3.线程类中槽函数在哪个线程中执行的问题
由于线程本身就是通过信号/槽函数进行处理的,所以他们执行的线程相同,槽相应顺序可以通过第五参数设置。
具体需要参考,connect函数中表示连接方式得参数
如下:
同步调用:信号发出后,当前线程等待槽函数执行完毕才能执行剩余代码。
异步调用:信号发出后,立即执行剩余逻辑,不关心槽函数什么时候执行。
AutoConnection 信号和槽同一线程时,直接调用,不同线程时,队列调用;
DirectConnection 发送消息后立即调用槽函数;
QueueConnection 发送后插入队列,按照线程消息队列调用;
BlockingQueuedConnection 阻塞联,同步调用, 槽函数在次线程中执行,用信号量实现阻塞,
槽函数所在对象得线程必须启用QT事件循环,此连接只能用于发出信号得线程和槽函数执行线程不同得情况。
要么在发射信号得线程中执行要么在接受者依附得线程中执行

### Qt 中信号与槽的连接方式Qt 的信号与槽机制中,`QObject::connect()` 函数用于建立信号和槽之间的联系。以下是几种常见的连接方式及其对应的示例。 #### 1. 使用传统语法进行连接 传统的 `QObject::connect()` 方法通过字符串形式指定信号和槽的名字。这种方式适用于较旧版本的 Qt 和某些特定场景。 ```cpp // 假设有一个 QPushButton 对象 button 和一个 QLineEdit 对象 lineEdit QPushButton *button = new QPushButton(); QLineEdit *lineEdit = new QLineEdit(); // 将按钮点击信号 connect 到编辑框清空操作 QObject::connect(button, SIGNAL(clicked()), lineEdit, SLOT(clear())); ``` 此方法依赖于宏定义的信号和槽名称,在编译时不会检查其有效性[^4]。 --- #### 2. 使用现代 C++ lambda 表达式进行连接Qt 5 起支持使用 Lambda 表达式的现代化连接方式,这种方法提供了更强的类型安全性和灵活性。 ```cpp #include <QDebug> // 创建对象实例 QPushButton *button = new QPushButton(); QObject *object = new QObject(); // 使用 Lambda 表达式绑定信号到匿名函数 QObject::connect(button, &QPushButton::clicked, [=]() { qDebug() << "Button was clicked!"; }); // 绑定信号到成员函数 QObject::connect(button, &QPushButton::clicked, object, [object]() { object->doSomething(); // 假设有 doSomething 成员函数 }); ``` Lambda 方式允许开发者执行更复杂的逻辑而无需显式声明额外的槽函数[^3]。 --- #### 3. 不同线程间的信号与槽连接 当涉及多线程编程时,可以通过设置合适的连接类型实现线程间的安全通信。 ##### (a) **自动连接 (`Qt::AutoConnection`)** 这是默认的行为模式,由框架自行判断发送方和接收方是否处于同一线程并决定采用何种具体策略。 ```cpp // 默认情况下会尝试 Auto Connection QObject::connect(senderObject, &SenderClass::someSignal, receiverObject, &ReceiverClass::someSlot); ``` 如果两者位于不同线程,则实际效果相当于选择了 Queued Connection;否则为 Direct Connection[^1]。 ##### (b) **队列连接 (`Qt::QueuedConnection`)** 强制将信号放入目标线程的消息循环队列等待处理。 ```cpp // 明确指明要使用 Queue Connection 类型 QObject::connect(senderThreadObj, &MyEmitter::dataReady, workerThreadObj, &Worker::processData, Qt::QueuedConnection); ``` 这种类型的优点在于能够有效避免竞态条件等问题发生。 ##### (c) **直接连接 (`Qt::DirectConnection`)** 无论当前上下文如何都会立刻调用关联上的 Slot 处理程序。 ```cpp // 即使跨越线程也立即响应 QObject::connect(mainWindowBtn, &QPushButton::pressed, backgroundTaskRunner, &BackgroundTask::startWork, Qt::DirectConnection); ``` 需要注意的是在这种情形下可能会破坏预期顺序或者引发潜在的数据竞争风险。 --- ### 总结 上述展示了三种主要的 Signal-Slot 配置手段以及各自适用范围。无论是经典风格还是新型解决方案都各有千秋,应依据项目需求合理选用最恰当的形式完成任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值