網站首頁 編程語言 正文
引言
在之前的Qt項目中,我發現經常會用到槽函數只需要執行一次的情況。也就是說,槽函數執行一次后,就需要disconnect對應的連接。然而,真正操作起來實際上挺麻煩的,或者說不優雅。
因為你需要把之前connect時產生的QMetaObject::Connection
對象保存起來,而保存它不能用局部變量,通常需要保存到類的成員變量中,或者其他生命周期足夠長的地方,以防止在disconnect它的時候,它已經失效了。
總之,需要使用者自己維護,因而增加了使用者的負擔。
如果有一個方法能夠在槽函數執行完成后自動disconnect掉連接就好了。我在網上找了一段時間,卻沒有找到合適的解決方案,相關討論也比較少,可能這不是一個很常見的需求吧。不過還是在GitHub上找到了一個相關的庫:https://github.com/misje/once,但是看它的源碼,感覺比較復雜。
它針對QObject::connect
函數的每種情況,寫了對應的實現,總感覺太復雜了,應該存在一種更通用的方法。
最近在閱讀了《C++ Primer》模板相關的章節后,我突然想到也許用完美轉發相關的東西可以簡化實現。于是試著寫了一下,貌似真得可以,代碼如下:
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(); }
這個實現假定QObject::connect
的所有重載函數前兩個參數分別是Sender和Signal,事實上確實是這樣。關鍵點就是,額外建立一個連接,在收到信號后,disconnect用戶的連接。不過,我總感覺這個實現在多線程的情況下可能有bug,但在經過簡單的測試后,暫時沒有發現。
使用示例如下:
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"; });
原文鏈接:https://segmentfault.com/a/1190000042428429
相關推薦
- 2021-12-17 使用遞歸時返回結果是undefined的原因和解決辦法
- 2022-08-01 grpool?goroutine池協程管理_Golang
- 2021-12-22 Linux一次性計劃任務at命令使用詳解_Linux
- 2022-03-27 C語言中scanf與scnaf_s函數詳解_C 語言
- 2022-11-19 ElasticSearch事件查詢語言EQL操作_服務器其它
- 2022-06-12 QT?.pro文件使用解析_C 語言
- 2022-08-06 詳解Python如何優雅地解析命令行_python
- 2022-04-28 C語言動態開辟內存詳解_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支