Qt 5 Alpha 已经发布。我们会在后面的文章中看到 Qt 5 的新变化。今天,我们先来看一下 Qt 5 带来的一个最主要的变化:signal/slot 机制的改变。

Qt 5 之前的语法

在 Qt 5 之前,我们需要使用下面的语句来链接 signal 和 slot:

1
2

connect(sender, SIGNAL(valueChanged(QString, QString)),
        receiver, SLOT(updateValue(QString)));

Qt 实际上利用SIGNALSLOT这两个宏,把其后的函数名转换成一个字符串。随后,moc 将会扫描全部文件,将所有的 signal 和 slot 提取出来做成一个映射表。QObject::connect()函数则会从这个映射表里面找到该字符串,从 signal 的名字就可以找到 slot 的名字,因此也就知道了在 signal emit 的时候,该去调用哪一个 slot 函数。

Qt 5 之前的 signal/slot 语法的问题

从上面的解释可以看出,Qt 5 之前版本提供的这种语法其实有一些问题:

  • 没有编译期检查:因为函数名被处理成字符串,所有的检查都是在运行时完成的。这就是为什么有时会发生编译通过了,但 slot 并没有被调用。此时,你就应该去检查 console 的输出,看看有没有什么 warning 说明 connect 并没有成功。
  • 因为处理的是字符串,所以 slot 中的类型名字必须用 signal 的完全一致,而且在头文件中的和实际 connect 语句中的也必须一致。也就是说,如果你使用了 typedef 或者 namespace,connect 就可能不成功(在 Qt 5 之前的版本中,我们当然也可以使用 namespace,但是必须保证头文件中的和 connect 语句中的文本完全一致)。

新语法:使用函数指针

在 Qt5 提供了一套新的语法。之前的语法依然可以使用,但是现在,我们有了更好的选择:

1
2

connect(sender,&Sender::valueChanged,
        receiver,&Receiver::updateValue);

这个看起来和之前的版本很类似,因此很容易迁移到新的语法。下面我们看看新语法有什么好处:

编译器检查

如果把 signal 或者 slot 名字编写错误,或者 slot 的参数同 signal 不一致,你会在编译期就获得一个错误。这肯定会在重构、或者修改 signal 或 slot 的名字时节省很多时间。

另一个影响是,Qt 可以利用static_cast返回更友好的错误信息。例如,如果我们少了Q_OBJECT宏,则会有:

1
2
3
4
5
6
7
8
9

#include <QtCore/QtCore>
class Goo : public QObject {
    Goo() {
        connect(this, &Goo::someSignal, this, &QObject::deleteLater);
    }
signals:
    void someSignal();
};

其错误信息是:

1
2
3
4
5

qobject.h:Inmemberfunction'void QObject::qt_check_for_QOBJECT_macro(const T&) const [with T = Goo]':
qobject.h:535:9:  instantiatedfrom'static typename QtPrivate::QEnableIf::ArgumentCount) >= (int)(QtPrivate::FunctionPointer::ArgumentCount)), void*>::Type QObject::connect(const typename QtPrivate::FunctionPointer::Object*, Func1, const typename QtPrivate::FunctionPointer::Object*, Func2, Qt::ConnectionType) [with Func1 = void (Goo::*)(), Func2 = void (QObject::*)(), typename QtPrivate::QEnableIf::ArgumentCount) >= (int)(QtPrivate::FunctionPointer::ArgumentCount)), void*>::Type = void*, typename QtPrivate::FunctionPointer::Object = Goo, typename QtPrivate::FunctionPointer::Object = QObject]'
main.cc:4:68:  instantiatedfromhere
qobject.h:353:5:error:voidvaluenotignoredasitoughttobe
make:***[main.o]Error1

参数的自动类型转换

现在,我们不仅可以更好地使用 typedef 或 namespace,而且可以利用隐式类型转换。在下面的例子中,我们的 signal 有一个QString参数,而 slot 需要的是QVariant。在新语法中,QString将被自动转换成QVariant

1
2
3
4
5
6
7
8
9
10
11
12

class Test : public QObject
{
    Q_OBJECT
public:
    Test() {
        connect(this, &Test::someSignal, this, &Test::someSlot);
    }
signals:
    void someSignal(const QString &);
public:
    void someSlot(const QVariant &);
};

连接到任意函数

如果你留心上面的例子,就会发现,我们的 signal 被连接到了一个 public 函数,但这个函数并不是 slot。Qt 的新语法通过函数指针直接调用函数,而不需要 moc 的特殊处理(但是 signal 依然需要)。

更进一步,我们可以将 signal 连接到任意函数:

1
2
3
4
5
6

staticvoidsomeFunction(){
    qDebug()<<"pressed";
}
// ... somewhere else
QObject::connect(button,&QPushButton::clicked,someFunction);

这样处理,就可以让你很方便的同 boost 或者 tr1::bind 这样的第三方库协作。

C++11 lambda 表达式

至此之前,我们所有的示例都是基于 C++98. 标准的。但是,如果你的编译器支持 C++11,我相信你一看到“函数指针”这几个字,就一定会想到 C++11 的新特性:Lambda 表达式。现在,Lambda 表达式至少被 MSVC 2010,GCC 4.5,clang 3.1 这几个编译器支持。不过对于后面两个编译器,你需要在编译时加上 -std=c++0x 参数。

现在我们可以用 Lambda 表达式重写了:

1
2
3
4
5
6
7
8
9
10
11

voidMyWindow::saveDocumentAs(){
    QFileDialog *dlg=newQFileDialog();
    dlg->open();
    QObject::connect(dlg,&QDialog::finished,[=](intresult){
        if(result){
            QFilefile(dlg->selectedFiles().first());
            // ... save document here ...
        }
        dlg->deleteLater();
    });
}

这种语法允许我们更方便地编写异步代码。

Qt5 中的 signal/slot 新语法相关推荐

  1. qt中emit signal slot

    qt中emit signal slot qt中的类库有很多都是从QObject上继承下来的, 信号与反应槽(signals/slot)机制就是用来在QObject类或其子类之间通信的一种方法.作为一种 ...

  2. .NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

    开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以, ...

  3. .NET中那些所谓的新语法之四:标准查询运算符与LINQ

    开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运算符是定义在System.Linq.Enumerable类中的50 ...

  4. c#中的反射的高级语法_Kubernetes第3部分中的seccomp新语法以及一些高级主题

    c#中的反射的高级语法 On this part I want to cover a few isolated points that hopefully together would give a ...

  5. qurlinfo在qt5中_QT5编译使用QFtp的方法步骤

    背景 使用 QNetworkAccessManager 可以实现 Ftp 的上传/下载功能,但它没有提供例如list.cd.remove.mkdir.rmdir.rename 等功能.这种情况下,我们 ...

  6. Qt5下OpenGL程序的新写法

    在Qt5中,引入了QOpenGL*系列类,以取代Qt4时代的QGL*系列类. 下面是从Qt5例子中抠出的两种OpenGL程序模板,方便参考. 第一种写法: #ifndef TRIANGLEWINDOW ...

  7. Qt signal slot 实现机制

    今天被问到一个问题,如下:Qt的signal slot的实现机制. 现在整理一下: 概述 信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解.信号和槽是一种高级接口,应用于对象之间的 ...

  8. QT中的Singal\slot机制

    QT中的Singal\slot机制 在QT工程项目中,会使用到多窗口或者二级窗口,而窗口之间做数据交流时,可以使用信号\槽机制,将两个不相关的对象相连,达到数据传输的效果. 语法 Connect函数 ...

  9. slot传函数 vue_vue中的插槽slot理解

    本篇文章参考赛冷思的个人博客 1.函数默认传参 在我们写js函数我们的可能会给他们一个默认的参数,写法是 functionshow(age,name){var age = age || 20;var ...

最新文章

  1. AI时代数据之争,我们需要什么样的“数据权”?
  2. ubuntu修改根用户密码
  3. 节能与新能源汽车技术路线图2.0_节能与新能源汽车技术路线图(2.0版)
  4. 使用 Fluent API 配置/映射属性和类型
  5. mybatis入门常见错误
  6. 【maven】maven的介绍
  7. 详细讲解怎样做数据仓库需求分析
  8. 修改linux文本模式下的分辨率
  9. 软件工程之系统建模篇【设计接口类模型】
  10. 教育版AutoCAD下载开启,你知道吗?
  11. 使用scrapy爬取图片
  12. 设计模式------享元模式和组合模式
  13. 看到自己的体检报告,小灰瑟瑟发抖
  14. 现代检测技术课程实验编程:最小二乘法应用编程
  15. configure报错
  16. 问题事件名称: APPCRASH 应用程序名: xxx.EXE 应用程序版本:
  17. JS解混淆-AST还原案例
  18. 满分作文生成器网页版
  19. 推荐一款免费的SQLsever的备份软件sqlBackupAndFtp
  20. 【Python】爬取金庸射雕英雄传连载版以及金庸作品里所有江湖门派

热门文章

  1. Apache配置(转载)
  2. python用代码安装3.6_Python3.6安装及引入Requests库的实现方法
  3. 在哪里查看计算机配置的网络协议簇,tcp/ip协议簇
  4. A Simple Math Problem(矩阵快速幂)
  5. behavior php,behavior.php
  6. 二分检索用途及复杂性_二分查找和三分查找哪个快?算法复杂度与常数无关?复杂度分析的常见误区...
  7. systemverilog 关联数组
  8. linux捕获其他进程信号,linux进程如何捕获信号
  9. C++ 重载运算符 继承 多态 (超详细)
  10. 图书馆管理系统用户端心得