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 ...
随机推荐
- IOS之UI -- UITableView -- 1 -- 相关初识
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- (第五章)java面向对象之this的作用总结
this关键字总是指向调用该方法的对象. this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类的(在那个类中就是那个类), ...
- 【nginx】关于gzip压缩
有这么一段配置文件 gzip on # 默认值: gzip off # 开启或者关闭gzip模块 gzip_static off; # nginx对于静态文件的处理模块 # 该模块可以读取预先压缩的g ...
- FinanceJson
FinanceJson, 对Json的包装.底层使用jackson实现. 1. 生成节点 (1)在某个路径下添加某个节点 FinanceJson financeJsonInfo = FinanceJs ...
- 详细的图文教程来实现 eclipse环境下如何配置tomcat,并且把项目部署到Tomcat服务器上
很多初学,尤其自学JavaWeb的朋友首次在eclipse下配置tomcat时,总会有种难下手的感觉,在此,通过图文解说的方法,最直观的向大家演示一遍该配置过程. 第一部分:eclipse环境下如何配 ...
- 通过java的Runtime.getRuntime()和System.getProperties()来获取系统的信息
第一种,通过Runtime.getRuntime()来获取系统信息. 通过java来获取系统以下的信息: 主机名: OS 名称: OS 版本: OS 制造商: OS 配置: 独立工作站 ...
- Windows x86/ x64 Ring3层注入Dll总结
欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6012353.html 0x00.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线 ...
- phpcms v9 下拉菜单 二级 三级子栏目调用方法
很多网站的导航栏可以实现下拉二级菜单,三级菜单等效果,今天我们就来分享phpcms v9 支持下拉菜单的方法,可以支持无限子栏目调用,具体写法如下: <ul> {pc:content ac ...
- ssis trainning
1. 防止包打开后hang住,可以使用delay validation=false. 2.2008R2 configuration 起作用的优先级? 一是des ign time. 二是运行的时候指定 ...
- ZOJ 3157 Weapon --计算几何+树状数组
题意:给一些直线,问这些直线在直线x=L,x=R之间有多少个交点. 讲解见此文:http://blog.sina.com.cn/s/blog_778e7c6e0100q64a.html 首先将直线分别 ...