Qt多個信號連接同一個槽的方法

2020-12-11 程式設計師fearlazy

Qt的信號/槽機制給我們編程帶來了很大的便利。在多數的情況下,我們只需要一個信號對應一個槽就可以了。但有時候我們也會遇到多個信號對應一個槽的情況。比如說做一個計算器的小程序,界面上有10個按鈕分別對應0 - 9這幾個數字。按下這幾個按鈕處理的邏輯是類似的,所以我們完全沒有必要為每一個按鈕都寫一個槽來對應按鈕按下的信號。但是假如我們把10個按鈕的按下信號都連接到一個槽函數中,那麼槽函數又要怎麼區分此時按下的是哪個按鈕呢?要知道按鈕的按下信號是不帶參數的。

這時候QSignalMapper就能派生用場了。它可以將對象的信號轉發一個槽函數中。那麼具體該怎麼使用呢?舉個例子吧:

首先用QtCreator創建一個基於QWidget的程序,使用UI設計師在界面上拖6個按鈕。

接下來我們將使用QSignalMapper將這6個按鈕的信號都連接到一個槽函數中。

創建QSignalMapper對象,並將它的mapped信號連接到一個槽函數中,這個槽就是我們用來處理6個按鈕的地方。

mSignalMapper = new QSignalMapper(this); connect(mSignalMapper,SIGNAL(mapped(QWidget*)),this,SLOT(slotSignalMap(QWidget*)));

mapped信號有4個不同參數的版本,根據需求自行選擇。

2. 將QSignalMapper與按鈕關聯起來,使用QSignalMapper的setMapping函數。

mSignalMapper->setMapping(ui->pushButton,ui->pushButton); mSignalMapper->setMapping(ui->pushButton_2,ui->pushButton_2); mSignalMapper->setMapping(ui->pushButton_3,ui->pushButton_3); mSignalMapper->setMapping(ui->pushButton_4,ui->pushButton_4); mSignalMapper->setMapping(ui->pushButton_5,ui->pushButton_5); mSignalMapper->setMapping(ui->pushButton_6,ui->pushButton_6);

setMapping有4個重載函數,參數類型與mapped信號的參數一一對應。

3. 將按鈕的按下信號與QSignalMapper關聯起來。前面做了那麼多不就是為了信號連在一起嗎。

connect(ui->pushButton,SIGNAL(pressed()),mSignalMapper,SLOT(map())); connect(ui->pushButton_2,SIGNAL(pressed()),mSignalMapper,SLOT(map())); connect(ui->pushButton_3,SIGNAL(pressed()),mSignalMapper,SLOT(map())); connect(ui->pushButton_4,SIGNAL(pressed()),mSignalMapper,SLOT(map())); connect(ui->pushButton_5,SIGNAL(pressed()),mSignalMapper,SLOT(map())); connect(ui->pushButton_6,SIGNAL(pressed()),mSignalMapper,SLOT(map()));

這一步將各個按鈕的信號都連接到QSignalMapper的map()槽函數中。然後發射到第1步的slotSignalMap槽中。

4.在slotSignalMap處理

void Widget::slotSignalMap(QWidget* w){QPushButton* button = qobject_cast<QPushButton*>(w); if(NULL != button){ qDebug()<<"click:" + button->text(); }}

由於我們在關聯按鈕和QSignalMapper時(setMapping)將按鈕對象傳入,在mapped信號觸發時傳給槽函數slotSignal。我們只需要把這個參數QWiget轉換為QPushButton對象就自然知道此時按下的是哪個按鈕了。效果如圖:

使用QSignalMapper可以幫我們解決信號轉發的問題,不過感覺還是有點局限性,我們可以看到信號最終是通過QSignalMapper的mapped()轉發出去的,如果我的QPushButton的兩個不同的信號都用QSignalMapper轉發會怎樣呢?

connect(ui->pushButton,SIGNAL(clicked(bool)),mSignalMapper,SLOT(map())); //clicked(信號) connect(ui->pushButton,SIGNAL(pressed()),mSignalMapper,SLOT(map())); //pressed(信號)

我們將第一個按鈕的clicked和pressed兩個信號都通過mSignalMapper轉發出去,點擊按鈕列印出了兩個"click:1"。

說明兩個信號都在同一個槽函數中處理了,這肯定不是我們想要的。我們既想要不同對象的同一個信號在同一個槽函數中處理,又不希望一個對象的不同信號在同一個槽函數中處理。怎麼辦?

看來還需要sender()函數來幫忙了。通過在槽函數中調用sender()來獲取信號的發送者。將上面的例子改一改,先定義一個slotClicked槽函數

void Widget::slotClicked(bool bcheck){QPushButton* button = qobject_cast<QPushButton*>(sender()); //將sender()轉為QPushButton if(NULL != button){ qDebug()<<"fearlazy click:"<<button->text()<<bcheck; }}

在槽函數中使用sender()獲取此時槽函數對應的信號發送者,返回類型是QObject。 這樣我們可以直接將不同對象的信號連接到同一個槽上,還能分清楚是誰觸發的。

connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool))); connect(ui->pushButton_2,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool))); connect(ui->pushButton_3,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool))); connect(ui->pushButton_4,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool))); connect(ui->pushButton_5,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool))); connect(ui->pushButton_6,SIGNAL(clicked(bool)),this,SLOT(slotClicked(bool)));

看看運行效果:

最後我們再添加一個slotPressed()槽函數,並讓第一個按鈕的pressed()信號連接該槽函數。

void Widget::slotPressed(){QPushButton* button = qobject_cast<QPushButton*>(sender()); if(NULL != button){ qDebug()<<"fearlazy pressed:"<<button->text(); //列印出presse了誰 }}connect(ui->pushButton,SIGNAL(pressed()),this,SLOT(slotPressed()));//在Widget的構造函數中連接

點擊第一個按鈕看看效果如何?

可以看到pressed和clicked信號都觸發了,而且兩個信號在不同的槽函數中處理。

測試環境:Qt5.9.4

相關焦點

  • PyQt 5信號與槽的幾種高級玩法
    在PyQt 5中信號與槽通過object.signal.connect()方法連接。PyQt的窗口控制項類中有很多內置信號,開發者也可以添加自定義信號。信號與槽具有如下特點。一個信號可以連接多個槽。一個信號可以連接另一個信號。信號參數可以是任何Python類型。一個槽可以監聽多個信號。
  • Qt信號槽原理
    ,返回staticMetaObject指針;方法qt_metacast(),原數據對象類型轉換,轉換成指定的類型,使用時一般傳入父類的名稱字符串;方法qt_metacall(),執行函數的回調,信號觸發;方法qt_static_metacall(),回調函數,被qt_metacall()調用,內部執行槽;這裡的幾個方法都沒有實現體,因為實現部分會有
  • qt 信號 多個參數 - CSDN
    ;主窗口中處理消息的兩個槽函數 //處理子窗口發送的第一個信號 void resume(); //處理子窗口發送的第二個信號,記住信號的返回值與參數和槽函數一定要一致 void realSub(int,QString);主窗口處理兩個消息
  • Qt的信號是私有還是公有
    所謂的信號(signals)和槽(slots)依然在C++語法範圍內,並沒有做出編譯器意義上的擴展。信號和槽本質上還是某個類的成員函數。  我們寫Qt信號是不需要實現的,這是因為Qt的moc工具會在編譯前給你實現了。比如在Qt5下類A的xxx信號的實現(用戶不需要操作)。
  • 信號與槽專題及常見問題 - CSDN
    如果存在多個槽與某個信號相關聯,那麼,當這個信號被發射時,這些槽將會一個接一個地被執行,但是它們執行的順序將會是不確定的,並且我們不能指定它們執行的順序。信號的聲明是在頭文件中進行的,QT的signals關鍵字指出進入了信號聲明區,隨後即可聲明自己的信號。信號由moc自動生成,所以不需要在cpp中定義,只需要聲明,信號的返回類型都是void。
  • 密集型母線槽連接示意圖和安裝母線槽方法
    密集型母線槽連接示意圖和安裝母線槽方法。現在電力系統進行安裝了母線槽電氣設備,這種設備能夠安全輸送大電流,購買時要保證設備質量,以免使用過程中出現問題。那麼,進行安裝密集型母線槽時,採用什麼樣方法呢?跟著小編一起了解下吧。
  • java 信號與槽專題及常見問題 - CSDN
    QT信號/槽在我的理解中,QT和Android都是類似的開發框架,都是由開發團隊封裝了各式各樣的接口和數據結構.將一些問題的解決方法簡單化 比如QT中將線程封裝為QThread,派生類通過重寫run方法來將代碼投入到新的線程執行,而同樣的Android中的線程是Java自帶的Thread
  • QT攝像頭調用(為OpenCV人臉識別做鋪墊)--- Qt(五)
    攝像機對象被設置為'0',用戶界面被初始化,UI信號連接到對觸發事件作出反應的槽。然而,大多數工作都是在調用setCamera()函數時完成的,並傳入QByteArray。【看來qt/VS也是設置『0』,才啟用。調用setCamera完成相關設置,這點和串口setpost一樣】問題來了?一個漢字多少字節?
  • 學習qt07QtCreator技巧
    qt擴展了元對象,信號與槽,屬性.在類中私處聲明Q_OBJECT宏,生成能夠支持元對象代碼的c++文件.metaObject返回元對象.其有許多接口,如QMetaObject::className()類名.newInstance新實例.inherits是否繼承某個串表示的類.tr和trUtf8可翻譯串,setProperty/property來取置屬性.
  • c++信號與槽專題及常見問題 - CSDN
    u012372584/131624962、直接編譯會有錯誤,需要對源碼中的一句進行更改:將第419行 :typedef sender_set::const_iterator const_iterator; 更改為:typedef typename sender_set::const_iterator const_iterator;3、使用:(1)、定義信號
  • Qt 國際化(下)
    information(NULL, tr("Path"), tr("You selected\n%1").arg(path));這句你當然可以寫成QMessageBox::information(NULL, tr("Path"), "You selected\n" + path);但這種連接字符串的方式就不能夠使用
  • Qt實例——主窗口和子窗口互發信號
    主窗口添加一個自定義信號:signals:void sendText(QString str);在主窗口構造函數裡添加 子窗口初始化代碼及信號槽連接代碼。Form *form = new Form;form->show(); //顯示窗口connect(this, &Widget::sendText, form, &Form::recText); //連接信號槽
  • c++ 槽函數專題及常見問題 - CSDN
    它是一種函數回調機制,當一個信號關聯了多個槽時,信號發出,這些槽將會被調用,當然,也可以僅僅關聯一個槽函數。>連接(connect)connection connect(const group_type &group,const slot_type &slot, connect_position position = at_back)它作為signal的成員函數,具有三個參數,第一個參數表示這個槽所屬的組,第二的參數表示信號觸發哪個槽函數,而最後的參數,表示槽函數在響應隊列中響應的位置
  • C++QT——Qt入門
    建立連接QObject::connect (button, SIGNAL(clicked()), &app, SLOT(quit()));通過使用發射信號(signal)來表明一個用戶動作已經發生了或者是一個狀態已經改變了。
  • qt 信號槽 - CSDN
    QT的信號槽機制用起來好用,看起來也比較清晰,隨時隨處可以綁定自己關係的信號,非常方便。而且提供異步,跨線程使用也很給力。在之前還想把這個機制擴展成一個專門處理任務的異步隊列,實驗後發現不可行,多次綁定和發出信號後內存就急劇上漲,最後分配不到內存了。
  • 母線槽與其他設備連接
    1、母線槽與變壓器、低壓櫃連接的母線走向應合理;搭接的母線與低壓櫃的母線規格應吻合。3、母線槽在接續設備端子前應可靠固定,電氣元器件或設備端子不得承受母線槽荷載。4、母線與電氣設備採用螺栓連接時.宜露出螺栓的螺紋2扣~ 3扣,平墊和彈簧墊應安裝齊全。裸露母線間的電氣間隙和爬電距離應符合國家標準(低壓成套開關設備和控制設備 第1部分:總則)GB /T 7251.1- -2013中第8.3. 1條的規定。
  • qt5.12下繼承於Qdialog的類調用slot函數編譯錯誤匯總
    最近由於項目需要,需要使用qt做一套連接資料庫並且實現用戶登錄,註冊的界面,但是做起來卻很費勁,出現了一堆奇怪的編譯錯誤。如果是這個錯誤,建議你先使用這個方法:使用vs調試器打開你的代碼,在文件中,找到高級保存選項,將代碼保存為代籤名的,然後保存。這個時候,在qt下先執行qmake,然後再重新構建,最後看一下是否還有錯誤。如果還是一堆堆的錯誤,那麼繼續把報錯的h文件和cpp文件,採用相同的保存方式。
  • 華為手機黑科技,WLAN信號橋科普及使用方法
    舊手機淘汰了,扔掉可惜,於是各種利用方法層出不窮。舊手機配置較低,各種利用方法基本都是用其網絡功能共享數據連接,還有攝像頭功能等。本文也不例外,少數華為手機上還有一個網絡功能「WLAN信號橋」。前面寫過幾篇介紹了舊手機的幾種網絡共享方法,手機移動數據通過熱點或usb共享網絡給設備;手機開啟wlan連接wifi後通過usb或藍牙共享網絡給電腦等。舊手機還可以安裝軟體當做行車記錄儀或家庭監控設備。
  • qt creator連接資料庫並實現用戶登錄和註冊相關的開發源碼詳解
    項目最終實現效果圖具體代碼詳解1 如何給qt界面設置相關的圖片呢?首先我們新建一個基於對話框的程序,名字自己定義即可。2 如何連接相關的資料庫,進行資料庫相關的調用關聯資料庫最重要的就是調用mysql進行相關的用戶註冊信息的記錄,我們為何要使用sql呢?是因為我們每次進行註冊的時候,都要進行相關的數據信息的登錄,從使用和存儲的性價比來看,資料庫是最好的選擇。