深入探究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/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

发表回复

登录后才能评论