深入探究Qt中的QSignalMapper

一、QSignalMapper用法

在Qt中,QSignalMapper是一個很有用的工具類,它可以將一個信號和多個對象進行關聯。當該信號被觸發時,QSignalMapper會發出自己的一個信號,同時在這個信號中傳遞與觸發的對象關聯的數據。

通常,我們可以使用QSignalMapper來處理一組控制項的觸發信號,比如QPushButton的clicked()信號,使用QSignalMapper可以使每個按鈕觸發的操作都不同,這給我們的程序帶來了更靈活的設計。

接下來,我們來看一下QSignalMapper的使用方法。


// 創建QSignalMapper對象
QSignalMapper *mapper = new QSignalMapper(this);
 
// 創建QPushButton對象
QPushButton *btn1 = new QPushButton(tr("Button 1"));
QPushButton *btn2 = new QPushButton(tr("Button 2"));
 
// 信號與槽函數之間的關聯
connect(btn1, SIGNAL(clicked()), mapper, SLOT(map()));
connect(btn2, SIGNAL(clicked()), mapper, SLOT(map()));
 
// 將按鈕與數據相關聯
mapper->setMapping(btn1, "Button 1 clicked");
mapper->setMapping(btn2, "Button 2 clicked");
 
// 連接QSignalMapper自己的信號
connect(mapper, SIGNAL(mapped(QString)), this, SLOT(handleButton(QString)));

上面的例子中,我們先創建了一個QSignalMapper對象,並創建了兩個QPushButton對象。接著,使用connect()將兩個QPushButton對象的clicked()信號與QSignalMapper對象的map()槽函數關聯起來,將QPushButton對象與相關聯的數據(這裡是QString)使用setMapping()方法進行關聯。最後連接QSignalMapper自己的mapped()信號到handleButton()槽函數上。

當我們點擊QPushButton對象時,每個按鈕觸發的操作都會被區別對待,並且操作的具體內容會在handleButton()槽函數中處理。

二、QSignalMapper Mapping

在上一節中,我們使用setMapping()方法將QPushButton對象與QString數據相關聯。實際上,QSignalMapper可以與任意類型的QObject對象進行相關聯。

另外,使用QSignalMapper的一個重要技巧是將整個對象作為映射,而不是對象的一個屬性。這意味著如果想要對一個控制項發射信號並提供額外的信息,我們可以將該控制項本身作為映射,在槽函數中獲取所有需要的相關信息。

下面是一個基於QSignalMapper的完整的代碼示例:


#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
class Widget : public QWidget
{
  Q_OBJECT
 
public:
  explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
  {
     // 創建QSignalMapper對象
     mapper = new QSignalMapper(this);
 
     // 創建標籤
     QLabel *label = new QLabel(tr("Click any button"));
     layout()->addWidget(label);
 
     // 創建QPushButton對象
     QVariantMap properties{{"text", tr("Button 1")}, {"tag", 1234}};
     QPushButton *btn1 = createPushButton(properties);
 
     properties.replace("text", tr("Button 2"), "tag", 5678);
     QPushButton *btn2 = createPushButton(properties);
 
     // 信號與槽函數之間的關聯
     connect(btn1, SIGNAL(clicked()), mapper, SLOT(map()));
     connect(btn2, SIGNAL(clicked()), mapper, SLOT(map()));
 
     // 將按鈕與數據相關聯
     mapper->setMapping(btn1, btn1);
     mapper->setMapping(btn2, btn2);
 
     // 連接QSignalMapper自己的信號
     connect(mapper, SIGNAL(mapped(QObject*)), this, SLOT(handleButton(QObject*)));
 
     setLayout(new QVBoxLayout());
     layout()->addWidget(btn1);
     layout()->addWidget(btn2);
  }
 
public slots:
  void handleButton(QObject *obj)
  {
     QPushButton *button = qobject_cast(obj);
     QVariantMap properties = button->property("attributes").toMap();
 
     QMessageBox::information(this, "Info", QString("Button clicked!\n"
                                                     "Text: %1\n"
                                                     "Tag: %2\n").arg(properties["text"].toString(),
                                                                     properties["tag"].toInt()));
  }
 
private:
  QPushButton* createPushButton(const QVariantMap &properties)
  {
     QPushButton *button = new QPushButton(this);
     button->setProperty("attributes", QVariant(properties));
     button->setText(properties.value("text").toString());
 
     return button;
  }
 
  QSignalMapper *mapper;
};
 
int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Widget w;
  w.show();
  return a.exec();
}

上面例子中,我們創建了一個QPushButton對象,並關聯了兩個數據:text和tag。我們使用QVariantMap將數據存儲在屬性中,並使用setMapping()方法將QPushButton對象與自身相關聯。在handleButton()槽函數中,我們使用qobject_cast()將QObject對象強制轉換為QPushButton對象,並從其屬性中檢索相關信息進行處理。

三、QSignalMapper替代類

雖然QSignalMapper是一個非常實用的工具類,但在一些簡單的應用程序中,它可能會顯得過於笨重和複雜。Qt提供了許多替代QSignalMapper的方法。

QObject::sender()方法經常被用來獲取發射信號的對象。當信號觸發時,QObject::sender()會返回最後一個發射信號的對象。

於是,我們可以在槽函數中使用switch()或者if()等條件語句對不同的對象進行判斷,並執行對應的操作。

下面以一個簡單的例子來演示如何使用QObject::sender()方法替代QSignalMapper:


#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
class Widget : public QWidget
{
  Q_OBJECT
 
public:
  explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
  {
     QPushButton *btn1 = new QPushButton(tr("Button 1"));
     QPushButton *btn2 = new QPushButton(tr("Button 2"));
 
     connect(btn1, SIGNAL(clicked()), this, SLOT(handleButton()));
     connect(btn2, SIGNAL(clicked()), this, SLOT(handleButton()));
 
     setLayout(new QVBoxLayout());
     layout()->addWidget(btn1);
     layout()->addWidget(btn2);
  }
 
public slots:
  void handleButton()
  {
     QPushButton *button = qobject_cast(sender());
     if(button == nullptr) { return; }
 
     qDebug() <text());
  }
};
 
int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Widget w;
  w.show();
  return a.exec();
}

上面例子中,我們創建了兩個QPushButton對象,並使用QObject::sender()方法檢索哪一個QPushButton發射了信號。在槽函數中使用qobject_cast()將QObject對象強制轉換為QPushButton對象,並輸出該QPushButton對象的文本。

四、QSignalMapper獲取信號發射對象選取

有時候,我們想在控制項中保存一些數據,而不想使用屬性。在這種情況下,我們可以使用QWidget::setUserData()和QWidget::userData()來保存控制項的相關信息。使用QSignalMapper是很方便的,我們可以將保存在QWidget::userData()中的數據直接傳遞到槽函數中。

下面是一段代碼示例,演示如何使用QWidget::userData():


#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
class Widget : public QWidget
{
  Q_OBJECT
 
public:
  explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
  {
     QPushButton *btn1 = new QPushButton(tr("Button 1"));
     QPushButton *btn2 = new QPushButton(tr("Button 2"));
 
     btn1->setUserData(0, QVariant(1234));
     btn2->setUserData(0, QVariant(5678));
 
     connect(btn1, SIGNAL(clicked()), this, SLOT(handleButton()));
     connect(btn2, SIGNAL(clicked()), this, SLOT(handleButton()));
 
     setLayout(new QVBoxLayout());
     layout()->addWidget(btn1);
     layout()->addWidget(btn2);
  }
 
public slots:
  void handleButton()
  {
     QPushButton *button = qobject_cast(sender());
     if(button == nullptr) { return; }
 
     QVariant data = button->userData(0);
     if(data.isValid() && data.type() == QVariant::Int) {
         qDebug() <text(), data.toInt());
     }
  }
};
 
int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Widget w;
  w.show();
  return a.exec();
}

上面例子中,我們創建了兩個QPushButton對象,並使用QWidget::setUserData()將其與QVariant對象相關聯。在槽函數中,我們使用qobject_cast()檢索sender()對象,並使用QWidget::userData()獲取已關聯的數據。

五、總結

QSignalMapper是一個非常有用的工具類,可以使我們處理多個控制項發射的信號更加靈活。使用QSignalMapper,可以將一個信號和多個對象進行關聯。當該信號被觸發時,QSignalMapper會發出自己的一個信號,同時在這個信號中傳遞與觸發的對象關聯的數據。

另外,QObject::sender()方法是一個方便的替代QSignalMapper的方式。當信號被觸發時,可以使用QObject::sender()獲取發射信號的對象,並使用qobject_cast()將QObject對象強制轉換為實際的控制項對象。

最後,在控制項中保存數據時,可以使用QWidget::userData()和QWidget::setUserData()方法,將控制項與QVariant對象相關聯。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/231969.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-11 01:08
下一篇 2024-12-11 01:08

相關推薦

  • Qt雷達探測教程

    本文主要介紹如何使用Qt開發雷達探測程序,並展示一個簡單的雷達探測示例。 一、環境準備 在開始本教程之前,需要確保你的開發環境已經安裝Qt和Qt Creator。如果沒有安裝,可以…

    編程 2025-04-29
  • Qt State Machine與狀態機模式

    本文將介紹Qt State Machine和狀態機模式在Qt中的實現。Qt提供了QStateMachine和QState兩個類,可以方便地實現狀態機模式,並且能有效地處理複雜的、多…

    編程 2025-04-27
  • Python中的Qt庫

    Qt庫是一個跨平台的C++圖形用戶界面(GUI)工具包。它提供了豐富的界面控制項和處理系統事件的功能,可以輕鬆創建交互界面、圖形化應用和多媒體應用。而Python中的Qt庫則是Qt的…

    編程 2025-04-27
  • xmake qt:構建Qt應用的全流程解決方案

    本文將會詳細闡述xmake qt的使用方法以及其能夠解決的問題。針對Qt應用開發中的各種困境,xmake提供了一整套的解決方案,包括自動構建、依賴管理、部署打包等,極大地提高了開發…

    編程 2025-04-27
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、位元組與比特 在討論byte轉int之前,我們需要了解位元組和比特的概念。位元組是計算機存儲單位的一種,通常表示8個比特(bit),即1位元組=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25
  • Qt延時函數詳解

    一、概述 Qt提供了多種延時函數,用於實現程序中需要暫停一段時間的功能。Qt的延時函數分為線程休眠(sleep())、定時器(QTimer)和事件循環(QEventLoop)三種方…

    編程 2025-04-25
  • 深入了解scala-maven-plugin

    一、簡介 Scala-maven-plugin 是一個創造和管理 Scala 項目的maven插件,它可以自動生成基本項目結構、依賴配置、Scala文件等。使用它可以使我們專註於代…

    編程 2025-04-25

發表回復

登錄後才能評論