QSignalMapper的使用和使用场景

QSignalMapper类收集了一系列的无参信号,然后使用相对于信号发送者来说的整数、字符串或控件参数来重新发送它们。(一开始没读懂没关系,看完就懂了)

常见场景

其实,该类的一个典型的使用场合是,大量控件都要相应槽函数,而这些槽函数的实现又大致相同。这种情况下,最直接的办法就是仍然为每一个控件的相应信号创建一个槽函数。但这会导致代码的大量重复。此时,我们就可以使用QSignalMapper来实现这种需求。

  1. QSignalMapper类支持使用setMapping()函数将一个特定的整数或字符串和一个特定的对象关联起来。

  1. 可以将对象的信号(比如button的clicked)连接到QSignalMapper对象的map()槽函数上,而map()槽函数又会使用与对象相关联的整数或字符串来发送mapped()信号。

  2. 所以,我们只要将我们定义的一个槽函数连接到mapped()信号,即可处理大量相似控件的槽函数。

我们以一个例子来说明。其界面如下:(例子来自csdn第二篇文章,稍微的补充修改)

请仔细看补充的注释。将会对应上面写的三条。

初始化界面的代码如下:

void Widget::InitUi()
{
names << "宋江" << "卢俊义" << "吴用" << "公孙胜"
<< "关胜" << "林冲" << "秦明" << "呼延灼"
<< "花荣" << "柴进" << "李应" << "朱仝"
<< "鲁智深" << "武松" << "董平" << "张清";
QGridLayout *gridLayout = new QGridLayout;
for (int i = 0; i < names.size(); ++i)
{
QPushButton *button = new QPushButton(names[i]);
// 使用setMapping()函数将一个特定的整数或字符串或对象(qt doc截图那些)和一个特定的对象关联起来。
signalMapper->setMapping(button, names[i]);
// 这就是可以将对象的信号连接到QSignalMapper对象的map()槽函数上
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
gridLayout->addWidget(button, i / 4, i % 4);
}
// 将我们定义的槽函数连接到mapped()信号 // 注意看mapped的写法
connect(signalMapper, SIGNAL(mapped(QString)),this, SLOT(ShowName(QString)));
setLayout(gridLayout);
}

其中,names是一个私有的QStringList变量,存储每一个按钮上的文本内容。ShowName()是我们定义的一个槽函数,我们就是让所有按钮的clicked()信号都连接到这个槽函数。在窗口类中声明如下:

public slots:
void ShowName(QString name); private:
void InitUi(); private:
Ui::Widget *ui;
QSignalMapper* signalMapper;
QStringList names;

ShowName()槽函数的实现如下,简单的弹出一个消息框,显示当前点击的按钮的文本内容:

void Widget::ShowName(QString name)
{
QMessageBox::information(this, "Name", name);
}

当然,别忘了在构造函数中,调用我们的初始化界面的方法,以及实例化我们的signalMapper对象。如下:

ui->setupUi(this);
signalMapper = new QSignalMapper(this);
InitUi();

下面是参考。可看可不看

这篇写的不错,搬运为Markdown了 可以看一下

QSignalMapper类可以看成是信号的翻译和转发器。

它可以把一个无参的信号翻译成带int参数、QString参数、 QObject* 参数或者QWidget *参数的信号,并将之转发。

QSignalMapper类的功能核心是要建立一个从原始信号的object到需要的数据的映射(setMapper函数)。 map()作为QSignalMapper的一个槽函数,将根据setMapping规则转发mapped()信号。

QSignalMapper可将多个有类似处理方式signal用一个slot实现,相当于将N个一对一映射通过集中转换成多对一映射。

例子:有一堆button,可以把clicked()事件放在一个函数里进行处理,只要给button编个号或者给button起个名字就行,这样就不用给每个button写一个slot函数了,方便很多。

//mywidget.h
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0); signals: public slots:
//处理最终信号的槽
void doClicked(const QString &btnName); private:
QSignalMapper *signalMapper; };
//mywidget.cpp
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
QString buttonText = "btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,btn10";
QStringList textList = buttonText.split(",");
signalMapper = new QSignalMapper(this);
QGridLayout *gridLayout = new QGridLayout; for(int i=0; i<textList.size(); ++i)
{
//动态创建按钮
QPushButton *button = new QPushButton(textList[i]); //原始信号传递给signalMapper
connect(button,SIGNAL(clicked()),signalMapper,SLOT(map()));
//设置signalMapper的转发规则,转发为参数为QString类型的信号,并把textList[i]的内容作为实参传递
signalMapper->setMapping(button, textList[i]); gridLayout->addWidget(button, i/3, i%3);
} //将转发的信号连接到最终的槽函数上
connect(signalMapper,SIGNAL(mapped(QString)),this,SLOT(doClicked(QString))); setLayout(gridLayout);
} void MyWidget::doClicked(const QString &btnName)
{
//显示被按下的button名称
QMessageBox::information(this,"Clicked",btnName+" is clicked !");
}

例子说明:

首先把原始不带参数的信号连接到signalMapper的map()槽函数,这样signalMapper能在第一时间接收到原始信号;

其次调用setMapper方法建立映射关系,告诉signalMapper怎样处理原始信号。这个例子是把原始信号转化为一个带QString参数的信号;

最后接收转化后的带参数信号,这里把转化后的信号与槽函数连接,在槽函数中获得需要数据

映射关系可以通过removeMappings()移除;

setMapping函数的参数只有四种,并且要严格按照格式写入,第一种const QString&,第二种int,第三种QObject*,第四种QWidget *,对于后两种,需要的是他们的子类,则在信号处理的函数里进行类型转化.

参考

https://doc.qt.io/qt-5/qsignalmapper.html#details

https://blog.csdn.net/Amnes1a/article/details/70050788

https://blog.csdn.net/u011125673/article/details/51218196

https://blog.csdn.net/Amnes1a/article/details/70050788

QSignalMapper的使用和使用场景的更多相关文章

  1. 拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?

    写在前面 除了博文内容之外,和 netfocus 兄的讨论,也可以让你学到很多(至少我是这样),不要错过哦. 阅读目录: 迷雾森林 找回自我 开源地址 后记 毫无疑问,领域驱动设计的核心是领域模型,领 ...

  2. [NodeJS] 优缺点及适用场景讨论

    概述: NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. ...

  3. Asp.Net MVC中使用StreamReader读取“Post body”之应用场景。

    场景:有三个市场(Global.China.USA),对前台传过来的数据有些验证需要细化到每个市场去完成. 所以就出现了基类(Global)和派生类(China.USA) 定义基类(Global)Pe ...

  4. Java学习之反射机制及应用场景

    前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框 ...

  5. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  6. MVC常遇见的几个场景代码分享

    本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...

  7. RabbitMq应用一的补充(RabbitMQ的应用场景)

    直接进入正题. 一.异步处理 场景:发送手机验证码,邮件 传统古老处理方式如下图 这个流程,全部在主线程完成,注册->入库->发送邮件->发送短信,由于都在主线程,所以要等待每一步完 ...

  8. javascript之闭包理解以及应用场景

    半个月没写博文了,最近一直在弄小程序,感觉也没啥好写的. 之前读了js权威指南,也写了篇博文,但是实话实说当初看闭包确实还是一头雾水.现在时隔一个多月(当然这一段时间还是一直有在看闭包的相关知识)理解 ...

  9. TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析

    TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...

随机推荐

  1. Laya 吐槽日志.

    新换了一个公司,公司有两个产品都是用的laya, 一个as写的2D游戏, 一个ts写的3D游戏 as写小游戏,各种不舒服啊,  一堆 __JS这样的代码,   体验极差. laya IDE 按钮只能做 ...

  2. 08.DRF-反序列化

    三.反序列化使用 3.1 验证 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象. 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功 ...

  3. <react> 组件的详细介绍:

    <react> 组件的详细介绍: 思维导图: 代码介绍: TodoList:(组件) import React, { Component } from 'react' import Sty ...

  4. node.js 安装方法 以及 用原声搭建服务器

    node.js 安装方法: 第一步: 64位的安装包网址:   https://nodejs.org/dist/v4.4.3/node-v4.4.3-x64.msi 第二步: 进入命令提示框  输入 ...

  5. MySQL按指定字符合并及拆分

    按照指定字符进行合并或拆分是经常碰到的场景,MySQL在合并的写法上比较简单,但是按指定字符拆分相对比较麻烦一点(也就是要多写一些字符).本文将举例演示如何进行按照指定字符合并及拆分. 1. 合并 M ...

  6. 如何运用Linux进行查看tomcat日志

    第一步:进入tomcat目录下的logs.cd home /tomcat/logs 第二步:运行并查看日志:tail -f catalina.out 第三步:想终止查看:ctrl +c退出 第四步:比 ...

  7. 小程序被冻结,忘记原始ID,如何找回?

     登录成功,提示被冻结,选择"账号找回": 阅读须知:账号类型选择“小程序”,需要输入小程序的原始ID,此时已经不记得了~~ 微信:搜索 “ 公众平台安全助手 ” 并关注  点击查 ...

  8. vue+elementUI 图片上传问题

    图片上传问题,获取后台的图片,并点击可以更换图片,并把图片存储到数据库中: (1)在编辑页面上,action指的图片上传的地址,header指请求头: (2)因为element-ui有自己上传的接口, ...

  9. 开源导入导出库Magicodes.IE 多sheet导入教程

    原文作者:tanyongzheng 多Sheet导入教程 说明 本教程主要说明如何使用Magicodes.IE.Excel完成多个Sheet数据的Excel导入. 要点 多个相同格式的Sheet数据导 ...

  10. mysql常用时间函数与类型转换

    一.用到的函数有: 1.时间格式化函数  DATE_FORMAT(date,format) 2.时间加减函数DATE_ADD(date,INTERVAL expr unit)DATE_SUB(date ...