QT信号槽的在不同线程或者在同一线程下的连接方式

最近使用一个QTreeWidget加载数据库数据然后以tree的方式展现出来。
于是在读取数据库的时候新建一个线程的来读取数据库,读取数据完毕之后,再树形控件上显示出来。
新建线程的目的是为了防止读取大数据的时候出现界面阻塞的情况,提供用户体验。然后数据读取完毕之后,是不能在工作线程中把读取到的数据显示出来的,
必须传到主界面上显示出来。只是就会使用信号槽的方式把读取的数据传到主界面。

信号槽的连接方式有以下几种:
Qt::AutoConnection - 自动关联,这是默认值。如果信号和槽函数在同一个线程(包括在同一主线程或者在同一工作线程)中,则使用Qt::DirectConnection方式,
如果信号和槽函数没有在同一个线程中,则使用Qt::QueuedConnection
在信号发送的时候,决定采用哪种关联类型。
Qt::DirectConnection - 直接关联。信号和槽函数在同一个线程中,发射完信号后立即调用槽函数,只用在槽函数执行完成返回后,发射信号后面的代码才可以执行,相当于阻塞模式,和MFC中的SendMessage相同
Qt::QueuedConnection - 队列关联。信号和槽函数不再同一个线程中,当发送信号的线程发送信号后立即执行下面的代码,发送的信号会放到另一个线程的信号队列中等待获取执行,相当于不阻塞模式,和MFC中的PostMessage相同
Qt::BlockingQueuedConnection - 阻塞队列关联。信号和槽不再同一个线程中,发送信号的线程发送一个信号后,这个线程不会执行下面的代码,直到接收信号的线程中的槽函数执行完成返回后才会继续执行。
如果采用这种连接方式的信号和槽函数在同一个线程中,则会形成死锁。
Qt::UniqueConnection - 唯一关联。主要使信号发送者和接受者有唯一的连接。防止多次调用connect形成重复关联。一旦形成重复关联,信号一个旦发射,就会有对应的槽函数多次执行。

##1.信号和槽函数在同一个线程中的情况

class Test: public QMainWindow
{
    Q_OBJECT
Test()
signals:
	void sigFirst();
private slots:
	void slotFirst();
}

Test::Test(QWidget *parent)
: QMainWindow(parent) {
	ui.setupUi(this);
	for (int i = 0; i < 5; i++) {//采用默认方式,连接5次
		connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));
	}
	
	emit sigFirst();
}


void Test::slotFirst() {
	numCoon++;
	qDebug() << QStringLiteral("信号第")<<numCoon<<QStringLiteral("次连接");
}

运行之后的输出内容:

"信号第" 1 "次连接"
"信号第" 2 "次连接"
"信号第" 3 "次连接"
"信号第" 4 "次连接"
"信号第" 5 "次连接"`

如果代码修改一下,改为:

connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()), Qt::UniqueConnection);//注意第五个参数

再次运行一下,查看输出:

"信号第" 1 "次连接"

这次只发送了一次信号,但是咱们连接了5次,所以采用Qt::UniqueConnection方式连接,无论连接多少次,只发送一次信号,也只会执行一次槽函数

##2.信号和槽函数在不同线程中的情况
自定义线程类:

#pragma once

#include <QThread>

class QtTestThread : public QThread {
	Q_OBJECT

public:
	QtTestThread(QObject *parent);
	~QtTestThread();
protected:
	void run();
signals:
	void sigSecond();
};

#include "QtTestThread.h"
#include <QDebug>

QtTestThread::QtTestThread(QObject *parent)
: QThread(parent) {
}

QtTestThread::~QtTestThread() {
}

void QtTestThread::run() {
	emit sigSecond();
	qDebug() << QStringLiteral("信号发送完毕!");
}

调用线程类:

class QtTestThread;
class Test: public QMainWindow
{
    Q_OBJECT
Test()
signals:
	void sigFirst();
private slots:
	void slotThread();
private:
	QtTestThread* testThread;
}

#include "QtTestThread.h"
Test::Test(QWidget *parent)
: QMainWindow(parent) {
	ui.setupUi(this);
	
	testThread = new QtTestThread(this);
	connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()));//没有第五个参数,也就是采用默认的连接方式

	testThread->start();
}

void Test::slotThread() {
	qDebug() << QStringLiteral("线程发送的信号-槽函数执行!");
	QThread::sleep(3);
}

运行一下,输出内容:

"信号发送完毕!"
"线程发送的信号-槽函数执行!"

由此可以看出,信号发送完成信号后,就直接运行下面的代码了,而发送的信号就会被放到主线程的信号队列中等待执行。

咱们信号槽的连接方式修改一下,添加信号槽的连接方式 Qt::BlockingQueuedConnection:

connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::BlockingQueuedConnection);

再次运行一下:

"线程发送的信号-槽函数执行!"
"信号发送完毕!"//时间等待3秒之后才输出这句话

采用Qt::BlockingQueuedConnection的连接方式就实现了信号和槽函数的同步执行。
以上!

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值