C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)
引言
在之前的Qt項目中,我發(fā)現(xiàn)經常會用到槽函數(shù)只需要執(zhí)行一次的情況。也就是說,槽函數(shù)執(zhí)行一次后,就需要disconnect對應的連接。然而,真正操作起來實際上挺麻煩的,或者說不優(yōu)雅。
因為你需要把之前connect時產生的QMetaObject::Connection對象保存起來,而保存它不能用局部變量,通常需要保存到類的成員變量中,或者其他生命周期足夠長的地方,以防止在disconnect它的時候,它已經失效了。
總之,需要使用者自己維護,因而增加了使用者的負擔。
如果有一個方法能夠在槽函數(shù)執(zhí)行完成后自動disconnect掉連接就好了。我在網上找了一段時間,卻沒有找到合適的解決方案,相關討論也比較少,可能這不是一個很常見的需求吧。不過還是在GitHub上找到了一個相關的庫:https://github.com/misje/once,但是看它的源碼,感覺比較復雜。
它針對QObject::connect函數(shù)的每種情況,寫了對應的實現(xiàn),總感覺太復雜了,應該存在一種更通用的方法。
最近在閱讀了《C++ Primer》模板相關的章節(jié)后,我突然想到也許用完美轉發(fā)相關的東西可以簡化實現(xiàn)。于是試著寫了一下,貌似真得可以,代碼如下:
ConnectionUtil.h:
#pragma once
#include <QObject>
#include <QMap>
namespace ConnectionUtil
{
typedef QMetaObject::Connection Conn;
struct ConnKey {};
extern QMap<ConnKey*, QPair<Conn, Conn>> connMap;
class ReceiverObj : public QObject
{
Q_OBJECT
public:
explicit ReceiverObj(ConnKey *connKey) : key(connKey) {}
public slots:
void slot();
private:
ConnKey *key;
};
// 處理信號為SIGNAL(...)的情況
template <typename Sender, typename ...Args>
void connect(Sender &&sender, const char *signal, Args &&...args)
{
ConnKey *connKey = new ConnKey;
Conn conn1 = QObject::connect(std::forward<Sender>(sender), signal, std::forward<Args>(args)...);
Conn conn2 = QObject::connect(std::forward<Sender>(sender), signal, new ReceiverObj(connKey), SLOT(slot()));
connMap.insert(connKey, qMakePair(std::move(conn1), std::move(conn2)));
}
// 處理其他情況
template <typename Sender, typename Signal, typename ...Args>
void connect(Sender &&sender, Signal &&signal, Args &&...args)
{
ConnKey *connKey = new ConnKey;
Conn conn1 = QObject::connect(std::forward<Sender>(sender), std::forward<Signal>(signal), std::forward<Args>(args)...);
Conn conn2 = QObject::connect(std::forward<Sender>(sender), std::forward<Signal>(signal), [connKey] { ReceiverObj(connKey).slot(); });
connMap.insert(connKey, qMakePair(std::move(conn1), std::move(conn2)));
}
}ConnectionUtil.cpp:
#include "ConnectionUtil.h"
using namespace ConnectionUtil;
QMap<ConnKey *, QPair<Conn, Conn>> ConnectionUtil::connMap;
void ReceiverObj::slot()
{
const QPair<Conn, Conn> &connections = connMap.value(key);
QObject::disconnect(connections.first);
QObject::disconnect(connections.second);
connMap.remove(key);
delete key;
deleteLater();
}這個實現(xiàn)假定QObject::connect的所有重載函數(shù)前兩個參數(shù)分別是Sender和Signal,事實上確實是這樣。關鍵點就是,額外建立一個連接,在收到信號后,disconnect用戶的連接。不過,我總感覺這個實現(xiàn)在多線程的情況下可能有bug,但在經過簡單的測試后,暫時沒有發(fā)現(xiàn)。
使用示例如下:
ConnectionUtil::connect(this, SIGNAL(bong(int)), obj, SLOT(slotBong(int)), Qt::QueuedConnection);
ConnectionUtil::connect(this, &MainWindow::bong, obj, &SomeObject::slotBong, Qt::QueuedConnection);
ConnectionUtil::connect(this, &MainWindow::bong, this, []() {
qDebug() << "bingo";
});以上就是C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)的詳細內容,更多關于C++11 Qt connect函數(shù)的資料請關注腳本之家其它相關文章!
相關文章
C++ Qt開發(fā)之使用QHostInfo查詢主機地址
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應用程序,本文將重點介紹如何運用QHostInfo組件實現(xiàn)對主機地址查詢功能,希望對大家有所幫助2024-03-03
C語言中的pause()函數(shù)和alarm()函數(shù)以及sleep()函數(shù)
這篇文章主要介紹了C語言中的pause()函數(shù)和alarm()函數(shù)以及sleep()函數(shù),是C語言入門學習中的基礎知識,需要的朋友可以參考下2015-09-09

