https://blog.csdn.net/libaineu2004/article/details/86487354
connect用於連接qt的信號和槽,在qt編程過程中不可或缺。它其實有第五個參數,只是一般使用默認值,在滿足某些特殊需求的時候可能需要手動設置。
Qt::AutoConnection: 默認值,使用這個值則連接類型會在信號發送時決定。如果接收者和發送者在同一個線程,則自動使用Qt::DirectConnection類型。如果接收者和發送者不在一個線程,則自動使用Qt::QueuedConnection類型。
Qt::DirectConnection:槽函數會在信號發送的時候直接被調用,槽函數運行於信號發送者所在線程。效果看上去就像是直接在信號發送位置調用了槽函數。這個在多線程環境下比較危險,可能會造成奔潰。
Qt::QueuedConnection:槽函數在控制回到接收者所在線程的事件循環時被調用,槽函數運行於信號接收者所在線程。發送信號之后,槽函數不會立刻被調用,等到接收者的當前函數執行完,進入事件循環之后,槽函數才會被調用。多線程環境下一般用這個。
Qt::BlockingQueuedConnection:槽函數的調用時機與Qt::QueuedConnection一致,不過發送完信號后發送者所在線程會阻塞,直到槽函數運行完。接收者和發送者絕對不能在一個線程,否則程序會死鎖。在多線程間需要同步的場合可能需要這個。
Qt::UniqueConnection:這個flag可以通過按位或(|)與以上四個結合在一起使用。當這個flag設置時,當某個信號和槽已經連接時,再進行重復的連接就會失敗。也就是避免了重復連接。
QObject::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的連接方式就實現了信號和槽函數的同步執行。
--
完整的源碼如下:
頭文件:
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QThread> 6 7 namespace Ui { 8 class MainWindow; 9 } 10 11 class QtTestThread : public QThread { 12 Q_OBJECT 13 14 public: 15 QtTestThread(QObject *parent); 16 ~QtTestThread(); 17 18 protected: 19 void run(); 20 21 signals: 22 void sigSecond(); 23 }; 24 25 class MainWindow : public QMainWindow 26 { 27 Q_OBJECT 28 29 public: 30 explicit MainWindow(QWidget *parent = nullptr); 31 ~MainWindow(); 32 33 private: 34 Ui::MainWindow *ui; 35 36 signals: 37 void sigFirst(); 38 39 private slots: 40 void slotFirst(); 41 void slotThread(); 42 43 private: 44 QtTestThread* testThread; 45 int numCoon; 46 }; 47 48 #endif // MAINWINDOW_H
源文件:
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 #include <QDebug> 4 5 QtTestThread::QtTestThread(QObject *parent) 6 : QThread(parent) 7 { 8 } 9 10 QtTestThread::~QtTestThread() 11 { 12 } 13 14 void QtTestThread::run() 15 { 16 emit sigSecond(); 17 qDebug() << QStringLiteral("信號發送完畢!"); 18 } 19 20 MainWindow::MainWindow(QWidget *parent) : 21 QMainWindow(parent), 22 ui(new Ui::MainWindow) 23 { 24 ui->setupUi(this); 25 26 for (int i = 0; i < 5; i++) {//采用默認方式,連接5次 27 //connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));//沒有第五個參數,也就是采用默認的連接方式 28 connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()), Qt::UniqueConnection);//注意第五個參數 29 } 30 31 numCoon = 0; 32 //emit sigFirst(); 33 34 testThread = new QtTestThread(this); 35 //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()));//沒有第五個參數,也就是采用默認的連接方式 36 //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::QueuedConnection);//效果同上 37 connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::BlockingQueuedConnection);//效果不同 38 testThread->start(); 39 } 40 41 MainWindow::~MainWindow() 42 { 43 delete ui; 44 } 45 46 void MainWindow::slotFirst() 47 { 48 numCoon++; 49 qDebug() << QStringLiteral("信號第")<<numCoon<<QStringLiteral("次連接"); 50 } 51 52 void MainWindow::slotThread() 53 { 54 qDebug() << QStringLiteral("線程發送的信號-槽函數執行!"); 55 QThread::sleep(3); 56 }