Qt——信号槽连接:基于字符串与基于函数的连接之间的不同
从Qt5.0开始,Qt提供了两种不同的方式进行信号槽的连接:基于 字符串 的连接语法、基于 函数 的连接语法。这两种语法各有利弊,下面对它们的不同点进行总结。
以下几部分详细解释了它们之间的不同,并说明如何使用它们,以及各自的优点。
一、类型检查以及隐式类型转换
基于字符串的连接是在运行时通过字符串比较来进行类型检查,这种方式有3个局限性:
1.只有在程序运行后才能查出连接错误;
2.信号和槽之间不能进行隐式转换;
3.类型定义和名字空间不能被识别。
第2第3个局限存在的原因是,字符串的比较并不会涉及C++的类型信息,因此它严格依赖于字符串的匹配。
相反地,基于函数的连接由编译器进行检查,编译器在编译时捕捉错误,并且允许相容类型的隐式转换,而且它能识别相同类型的不同名称。
例如,信号有一个int类型的参数,而槽函数接受一个double类型的参数,只有基于函数的语法能够将他们连接起来。QSlider有一个int值,而QDubleSpinBox有一个double值,下面的代码段说明了如何将二者保持同步:
auto slider = new QSlider(this);
auto doubleSpinBox = new QDoubleSpinBox(this); // OK: The compiler can convert an int into a double
connect(slider, &QSlider::valueChanged,
doubleSpinBox, &QDoubleSpinBox::setValue); // ERROR: The string table doesn't contain conversion information
connect(slider, SIGNAL(valueChanged(int)),
doubleSpinBox, SLOT(setValue(double)));
下面的例子说明了名称识别的不足。
QAudioInput::stateChanged()声明时带有一个“QAudio::State”类型的参数,因此,基于字符串的连接也必须识别“QAudio::Satae”,即使“State”已经是可见的。这个特性并不适用于基于函数的连接,因为参数类型不是连接的一部分。
auto audioInput = new QAudioInput(QAudioFormat(), this);
auto widget = new QWidget(this); // OK
connect(audioInput, SIGNAL(stateChanged(QAudio::State)),
widget, SLOT(show())); // ERROR: The strings "State" and "QAudio::State" don't match
using namespace QAudio;
connect(audioInput, SIGNAL(stateChanged(State)),
widget, SLOT(show())); // ...
二、使用Lambda表达式进行连接
基于函数的连接语法可以将信号和C++11中的lambda表达式(实际上是内联的槽函数)连接起来,这个特性不适用与基于字符串的语法。
下面的例子中,类TextSender发出信号textCompleted(),该信号有一个QString类型的参数,下面是这个类的定义:
class TextSender : public QWidget {
Q_OBJECT
QLineEdit *lineEdit;
QPushButton *button;
signals:
void textCompleted(const QString& text) const;
public:
TextSender(QWidget *parent = nullptr);
};
下面是信号槽的连接,点击按钮时发出信号TextSender::textCompleted():
TextSender::TextSender(QWidget *parent) : QWidget(parent) {
lineEdit = new QLineEdit(this);
button = new QPushButton("Send", this);
connect(button, &QPushButton::clicked, [=] {
emit textCompleted(lineEdit->text());
});
// ...
}
在这个例子中,lambda函数使得连接变得很简单,即使QPushButton::clicked()和TextSender::textCompleted()有不匹配的参数。相反地,如果使用基于字符串的实现方式,则需要额外的代码。
注意:基于函数的连接语法接受所有函数的指针,包括普通的非成员函数以及成员函数,但为了可读性,信号应该只和槽、lambda表达式和其它信号连接。
三、连接C++对象和QML对象
基于字符串的语法可以连接C++对象和QML对象,但是基于函数的语法无法连接。因为QML类型在运行时识别,它们并不适用于C++编译器。
四、在槽中使用默认参数,与参数更少的信号进行连接
通常,只有在槽的参数小于等于信号的参数时,并且所有参数相匹配时,连接才能建立。
基于字符串的连接语法为这个规则提供了一个变通方案:当信号发出并且它的参数比槽的参数少时,如果槽有默认参数,这些参数可以从信号中省略,Qt使用默认值调用槽函数。
基于函数的连接不支持这种特性。
假如有一个叫做DemoWidget的类,槽函数printNumber()有一个默认参数:
public slots:
void printNumber(int number = 42) {
qDebug() << "Lucky number" << number;
}
使用基于字符串的连接,DemoWidget::printNumber()可以被连接到QApplication::aboutToQuit(),即使后者有更少的参数。基于函数的连接会在编译时报错:
DemoWidget::DemoWidget(QWidget *parent) : QWidget(parent) {
// OK: printNumber() will be called with a default value of 42
connect(qApp, SIGNAL(aboutToQuit()),
this, SLOT(printNumber()));
// ERROR: Compiler requires compatible arguments
connect(qApp, &QApplication::aboutToQuit,
this, &DemoWidget::printNumber);
}
五、选择重载信号或者槽
使用基于字符串的语法,参数类型是显式确定的。最后,使用哪个重载信号或槽是不明确的。
相反地,使用基于函数的语法,重载的信号或槽必须被强制转换,告诉编译器使用哪个。
例如,QSignalMapper有4种形式的mapped()信号:
1.QSignalMapper::mapped(int)
2.QSignalMapper::mapped(QString)
3.QSignalMapper::mapped(QWidget*)
4.QSignalMapper::mapped(QObject*)
为了连接int版本的QSpinBox::setValue(),两种语法写法如下:
auto mapper = new QSignalMapper(this);
auto spinBox = new QSpinBox(this); // String-based syntax
connect(mapper, SIGNAL(mapped(int)),
spinBox, SLOT(setValue(int))); // Functor-based syntax, first alternative
connect(mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
spinBox, &QSpinBox::setValue); // Functor-based syntax, second alternative
void (QSignalMapper::*mySignal)(int) = &QSignalMapper::mapped;
connect(mapper, mySignal,
spinBox, &QSpinBox::setValue);
Qt——信号槽连接:基于字符串与基于函数的连接之间的不同的更多相关文章
- Qt信号槽-原理分析
目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...
- Qt信号槽的一些事(第一次知道信号还有返回值,以及Qt::UniqueConnection)
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...
- Qt信号槽的一些事 Qt::带返回值的信号发射方式
一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值.那么如果我们发出这个信号想获取一个返回值怎么办呢? 两个办法:1.通过出参形式返回,引用或者指 ...
- Qt信号槽的一些事
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...
- Qt信号槽源码剖析(一)
大家好,我是IT文艺男,来自一线大厂的一线程序员 大家在使用Qt开发程序时,都知道怎么使用Qt的信号槽,但是Qt信号槽是怎么工作的? 大部分人仍然不知道:也就是说大家只知道怎么使用,却不知道基于什么原 ...
- QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类
一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如: QObject::connect: Can ...
- QT信号槽详解
1 QT信号槽详解 1.1 信号和槽的定义 信号是触发信号,例如按钮的点击触发一个clicked信号,槽是用来接收信号,并处理信号,相当于信号响应函数.一个信号可以关联多个槽函数,信 ...
- QT源码之Qt信号槽机制与事件机制的联系
QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...
- Qt信号槽源码剖析(二)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的基本概念.元对象编译器.示例代码以及Qt宏:今天接着深入分析,进入Qt信号槽源码剖析系列的第二节视频. Qt信号槽的宏 ...
- (文字版)Qt信号槽源码剖析(三)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的Qt宏展开推导:今天接着深入分析,进入Qt信号槽源码剖析系列的第三节视频. Qt信号槽宏推导归纳 #define si ...
随机推荐
- Spring(四)Bean注入方试
一.构造方法注入 定义:通过构造函数来完成依赖关系的设定 优缺点: 在构造对象的同时,完成依赖关系的建立 如果关联的对象很多,那和不得不在构造方法上加入过多的参数 基中有index:如果指定索引从0开 ...
- Jmeter之Http Cookie Manager
一.Http Cookie Manager的作用: 1.自动管理cookie:象浏览器一样的存储和发送Cookie,如果发送一个http请求他的响应中包含Cookie,那么Cookie Manager ...
- 【转载】主数据管理(MDM)与元数据管理
主数据(Master Data)和元数据(Meta Data)是两个完全不同的概念.元数据是指表示数据的相关信息,比如数据定义等,而主数据是指实例数据,比如产品目录信息等.比如,某省地税开发了一套 征 ...
- OOD沉思录 --- 类和对象的关系 --- 包含关系4
4.9 在实现语义约束时,最好根据类定义来实现.但是这经常会导致泛滥成灾的类,在这种情况下约束应当在类的行为中实现,通常在类的构造函数中实现,但不是必须如此. 还是以汽车为例,我们看汽车的定义,为了集 ...
- 5+ App开发入门指南
HTML5 Plus应用概述 HTML5 Plus移动App,简称5+App,是一种基于HTML.JS.CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任意调用手机的原生能力,实 ...
- 安装和配置JDK,并给出安装、配置JDK的步骤。
1.从orcal网站下载安装包. 2.安装目录不要有汉字或空格 3.配置环境变量,增加·JAVA_HOME=jdk的全路径,修改path+%JAVA_HOME%\bin;%JAVA_HOME%\jre ...
- Java GC 面试问题
转自:http://icyfenix.iteye.com/blog/715301 这个帖子的背景是今晚看到je上这张贴:http://www.iteye.com/topic/715256,心血来潮写下 ...
- Linux下Redis安装及配置
1.下载安装包 # cd ~/Download # wget http://download.redis.io/releases/redis-3.0.7.tar.gz --选择要下载的版本 ...
- 在VS2010中使用Outlook工具栏
参考资料:微软MSDN.VS2010示例代码 一开始上段子总是能活跃气氛,等哪天我再打开自己的这篇博客,总是能够让自己傻傻的乐一下. 我一女同学,毕业去一大公司应聘,竞争很激烈,最后剩下她和一位女士. ...
- 利用jsp和servlet,MySQL实现简易报表
beans包和jdbc包代码不放了,麻烦 Service.java: package service; import java.sql.Connection;import java.sql.Resul ...