net做網站軟文推廣代表平臺
Qt 信號與槽的使用詳解 - 多種綁定形式、同步異步、Lambda表達式等
- 引言
- 一、信號與槽常見的綁定形式
- 二、信號與槽的連接方式 - 同步異步
引言
在Qt框架中,信號與槽(Signals and Slots)機制是一種強大的通信方式,它允許對象之間進行通信而無需知道彼此的詳細實現。這種機制是Qt的核心特性之一,廣泛應用于事件處理和對象間的通信,能夠大大簡化編程的復雜性,提高代碼的可維護性和可擴展性。
一、信號與槽常見的綁定形式
使用connect
連接信號 (槽函數的參數個數必須小于等于信號函數的參數個數)
-
- connect函數指針 (
推薦
),例程如下:
QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
- connect函數指針 (
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中推薦的信號與槽連接語法,支持函數提示 - 函數補全,會在編譯時檢查到連接錯誤
-
- Lambda表達式(
推薦
) - 連接和槽函數的實現寫在一切,方便、簡潔且直觀,例程如下:
QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
- Lambda表達式(
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)
,少了接受者。
-
- 標準connect連接(
不推薦
) - QT4老語法,例程如下:
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
- 標準connect連接(
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)- 右鍵控件 - 點擊轉到槽 - 點擊相應的信號,自動生成相應的槽函數,默認綁定無需connect
2)- 在ui設計界面底部,添加信號和槽的對應關系,如下圖所示:
- 界面上設置
-
- …
一般用的不多的知識點:
- 將一個信號連接到另一個信號上,當第一個信號發(fā)射時,會觸發(fā)第二個信號
- 信號和槽可以重載,使用QOverload 和 QMetaObject::Connection處理重載信號和槽
- 一個信號可以連接多個槽,一個槽也能被多個信號連接
- 使用disconnect斷開信號和槽的連接
- 一個信號和一個槽函數和進行多次connect連接,一次觸發(fā)多次執(zhí)行… 可以設置連接類型來規(guī)避這種情況
UniqueConnection
- 發(fā)送信號不用加
emit
也行
可參考:
- Qt中connect()方法的一些常見用法:https://blog.csdn.net/weixin_42478379/article/details/137682367
- QT標準connect連接(QT4老語法):https://zhuanlan.zhihu.com/p/692721646
- QT 信號與槽4種綁定形式:https://blog.csdn.net/weixin_42127524/article/details/131189259
- 槽函數被執(zhí)行多次的解決方法及Qt::UniqueConnection作用及和其它連接類型的“與”操作寫法:https://blog.csdn.net/danshiming/article/details/123162126
- Qt信號槽/使用問題:https://blog.csdn.net/quguanxin/article/details/102843961
二、信號與槽的連接方式 - 同步異步
信號與槽的連接最后有一個枚舉參數Qt::ConnectionType type = Qt::AutoConnection
,默認自動。此參數主要表示信號是立即發(fā)出還是排隊等待:
常量 | 值 | |
---|---|---|
Qt::AutoConnection | 0 | (默認 ) 發(fā)送接收在同一線程,則Qt::DirectConnection,否則Qt::QueuedConnection |
Qt::DirectConnection | 1 | 發(fā)出信號時會立即槽函數,在信號發(fā)出者的線程中執(zhí)行。 |
Qt::QueuedConnection | 2 | 在接受者的事件循環(huán)(線程)中調用。- 異步 |
Qt::BlockingQueuedConnection | 3 | 和Qt::QueuedConnection 一樣,也在接受者線程中調用,但是發(fā)送信號的線程會被阻塞,直到槽函數執(zhí)行完畢 (防止槽函數和信號線程對某個值的操縱沖突)。 - 同步 |
Qt::UniqueConnection | 0x80 | 一個標志,可以與上述連接方式進行組合 保證同一信號和同一槽函數只能連接一次,再次connect連接會失敗。 |
- 對于排隊連接
Qt::QueuedConnection
,參數必須是Qt的元對象系統(tǒng)已知的類型,因為Qt需要復制參數以將其存儲在幕后事件中。如若是自定義類型,可以使用qRegisterMetaType()
注冊一下。- 對于
Qt::BlockingQueuedConnection
,不能用于發(fā)送者接受者在同一個線程的情況,會引起死鎖。 - (為啥?可參考博客:由Qt::BlockingQueuedConnection引起的關閉Qt主頁面而后臺仍有進程殘留:https://blog.csdn.net/youzai2017/article/details/132746319)- 當Lambda表達式作為槽函數時,記得使用以上推薦的方式,
寫全參數
。如果省略接受者,默認會在發(fā)送者的線程中直接執(zhí)行。- 比如一個線程發(fā)出信號,主線程(UI)線程響應修改相關UI,不寫接受者是主線程,會沖突報錯,因為只有主線程(UI)線程可以修改UI。