一   信号和槽

  GUI 程序除了要绘制控件,还要响应系统和用户事件,例如重绘、绘制完成、点击鼠标、敲击键盘等。当事件发生时,UI 会产生相应的变化,让用户直观地看到。
大部分编程(例如Win SDK、Web前端)中使用回调函数来响应事件,而 Qt 却独创了信号和槽机制。所谓回调函数,就是程序员提前定义一个函数,当事件发生时就调用该函数。
信号和槽是Qt的核心,它让两个互不相干的对象连接起来,当一个对象的状态改变时,可以通知另一个对象。
我们先通过例子来演示一下信号和槽:

具体的代码:

#include "mainwindow.h"
#include <QApplication>
#include <QMainWindow>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QMainWindow w;
    w.setWindowTitle("微浪游戏");
    w.resize(325, 120);

    QLineEdit lineEdit(&w);
    lineEdit.setGeometry(30, 20, 180, 36);
    lineEdit.setPlaceholderText("请输入文本");

    QPushButton btn("取消", &w);
    btn.setGeometry(220, 20, 70, 36);

    QLabel label(&w);
    label.setGeometry(30, 70, 250, 30);

    //连接clicke()信号和quit()槽
    QObject::connect(&btn, SIGNAL(clicked()), &app, SLOT(quit()));
    //连接textChanged()信号和setText()槽
    QObject::connect(&lineEdit, SIGNAL(textChanged(QString)), &label, SLOT(setText(QString)));

    w.show();
    return app.exec();
}

在上面的demo中创建了三个控件:lineEdit,btn,label,他们都是QMainWindow w的子控件。运行的结果如下:

点击“取消”按钮,程序就关闭了,这是第26行代码的作用;在文本输入框中输入一段文本,下面的 Label 会随时显示出来,这是第28行代码的作用。

这两个对象都是通过信号和槽连接起来的,信号和槽用于两个对象之间的通信。信号和槽是QT的核心特征,当一个特殊的事情发生时便可以发射一个信号,比如demo中的取消按钮被点击时,就会发射clicked()信号;而槽就是一个函数,它在信号发射后被调用来响应这个信号,Qt的部件类中已经定义了一些信号和槽,但是更常用的做法是子类化部件,然后添加自定义的信号和槽来实现想要的功能。

信号是只有函数声明、没有函数体的成员函数。槽是拥有完整函数体的普通成员函数,你可以在槽函数中实现各种功能,与普通函数相比并没有区别,例如 quit() 的作用就是退出程序。

connect() 是 QObject 类的静态成员函数;QObject 是 Qt 中所有类的基类,它就像“树根”,从这里派生出了所有其他“树枝”。
需要注意的是,信号不是事件。当用户点击“取消”按钮时,Qt 会捕获该点击事件,进行预处理,然后发射 clicked() 信号; clicked() 和 quit() 关联起来了,接下来就会调用 quit() 函数。
信号和槽机制归根结底也是回调函数,只不过绕了个圈子。在这种机制下,程序员有两次处理事件的机会,一是在捕获事件后发射信号前进行预处理(事件不符合预期可以不发射信号),二是在槽函数中进行主要处理。
再来看第27行。textChange() 信号会在文本改变时发出,setText() 槽用来设置 Label 的文本,QString
是要传递的数据的类型。当用户输入文本时,lineEdit 会发出 textChange() 信号,该信号将携带数据,数据类型为
QString,数据内容为输入的文本;setText() 槽接收到信号后先解析信号携带的数据,获取用户输入的文本,然后填充到 Label 中。

二 信号和槽的关联

信号和槽的关联使用的是QObject类的connect()函数,connect() 是 QObject 类的静态成员函数,它有多个原型:

connect(QObject *sender,   char *signal,
        QObject *receiver, char *method);
connect(QObject *sender,   PointerToMemberFunction signal,
        QObject *receiver, PointerToMemberFunction method);
connect(QObject *sender,   PointerToMemberFunction signal,
        QObject *context,  Functor functor);
connect(QObject *sender,   QMetaMethod &signal,
        QObject *receiver, QMetaMethod &method);
connect(QObject *sender,   PointerToMemberFunction signal,  Functor functor);

简单起见,上面省略了 connect() 的返回值和最后一个参数,以及某些参数前面的 const 修饰符,读者可以在 Qt 帮助手册中查看完整的原型。

connect() 函数返回值类型为QMetaObject::Connection,表示当前连接句柄。最后一个参数为Qt::ConnectionType type = Qt::AutoConnection,表示连接类型,一般默认即可。

观察上面的原型,除了最后一个有3个参数,其他都有4个参数,其中:
1) sender 为信号发送者,receiver 为信号接收者,它们都是对象指针。

2) 第1个原型中,signal 为信号,method 为槽函数,它们都是字符串,必须借助 SIGNAL() 和 SLOT()
将函数形式转换为字符串形式。SIGNAL() 和 SLOT() 是宏,而非函数。上面的示例中就使用了该原型,它是常用的原型,初学者必须要掌握。

3) 第2个原型中,PointerToMemberFunction 为指向成员函数的指针。你可以将示例中的代码做如下更改:

QObject::connect(&btn, &QPushButton::clicked, &app, &QApplication::quit);
QObject::connect(&lineEdit, &QLineEdit::textChanged, &label, &QLabel::setText);

这是 Qt 5 新增的原型,可以在编译期间进行检查,如果信号和槽不存在或者不匹配,则会报错。而第1种原型是从 Qt 诞生以来一直支持的,不能在编译期进行检测,如果信号和槽有误,只会在程序运行期间给出警告并返回 false,不容易发现问题,这是它的一个缺陷。所以在 Qt 5 中我们鼓励使用第2种原型。

QT Creator 快速入门教程 读书笔记(三)的更多相关文章

  1. QT Creator 快速入门教程 读书笔记(一)

    一 Qt简介 Qt 是一个跨平台的C++应用程序框架,支持Windows.Linux.Mac OS X.Android.iOS.Windows Phone.嵌入式系统等.也就是说,Qt 可以同时支持桌 ...

  2. QT Creator 快速入门教程 读书笔记(二)

    一 窗口部件 基础窗口部件QWidget类是所有用户界面对象的基类,窗口和控件都是直接或间接继承自 QWidget,下面我们来看一个很简单的例子: 窗口部件(Widget)简称部件,是QT中建立界面的 ...

  3. [Qt Creator 快速入门] 第1章 Qt Creator简介

    Qt Creator 是一个跨平台的.完整的 Qt 集成开发环境,其中包括了高级C++代码编辑器.项目和生成管理工具.集成的上下文相关的帮助系统.图形化调试器.代码管理和浏览工具等.这一章先对 Qt ...

  4. [Qt Creator 快速入门] 第2章 Qt程序编译和源码详解

    一.编写 Hello World Gui程序 Hello World程序就是让应用程序显示"Hello World"字符串.这是最简单的应用,但却包含了一个应用程序的基本要素,所以 ...

  5. [Qt Creator 快速入门] 第5章 应用程序主窗口

    对于日常见到的应用程序而言,许多都是基于主窗口的,主窗口中包含了菜单栏.工具栏.状态栏和中心区域等.这一章会详细介绍主窗口的每一个部分,还会涉及资源管理.富文本处理.拖放操作和文档打印等相关内容.重点 ...

  6. [Qt Creator 快速入门] 第0篇 开始学习Qt 与Qt Creator

    Qt官方信息 Qt官网:http://qt.digia.com/ Qt开源官网:http://qt-project.org/ Qt最新版本下载:http://qt-project.org/downlo ...

  7. [Qt Creator 快速入门] 第8章 界面外观

    一个完善的应用程序不仅应该有实用的功能,还要有一个漂亮的外观,这样才能使应用程序更加友好,更加吸引用户.作为一个跨平台的UI开发框架,Qt提供了强大而灵活的界面外观设计机制.这一章将学习在Qt中设计应 ...

  8. [Qt Creator 快速入门] 第3章 窗口部件

    从这一章开始正式接触Qt的窗口部件.在第2章曾看到 Qt Creator 提供的默认基类只有 QMainWindow.QWidget 和 QDialog 这3种.QMainWindow 是带有菜单栏和 ...

  9. [Qt Creator 快速入门] 第9章 国际化、帮助系统和Qt插件

    一.国际化 国际化的英文表述为Internationalization,通常简写为I18N(首尾字母加中间的字符数),一个应用程序的国际化就是使该应用程序可以让其他国家的用户使用的过程. Qt支持现在 ...

随机推荐

  1. Jenkins添加用户

    新建用户 Jenkins刚开始的界面是允许访客进行所有操作的,这时Jenkins是有安全隐患的,也不容易去管理.这时,我们需要管理Jenkins的权限,对它的权限进行设置.关于Jenkins权限设置的 ...

  2. android 项目更改包名的方法

    本文章全文转载: http://www.2cto.com/kf/201304/206747.html 1.在项目上右键,选择android tools->rename application p ...

  3. Ubuntu纯字符界面的一些设置

    由于Ubuntu的纯字符界面不支持中文显示,所以进行了一些配置,为了更好的显示 1. 把环境语言配置为英文 在用户目录下的".bashrc"文件的结尾处添加以下内容,然后重新登录 ...

  4. 读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式

    1. 一个错误释放内存的例子 下面的场景会有什么错? std::]; ... delete stringArray 一切看上去都是有序的.new匹配了一个delete.但有一些地方确实是错了.程序的行 ...

  5. [Linux] - xxx 不在 sudoers 文件中。此事将被报告。

    redhat系统: linux中创建用户命令为:useradd 用户名, eg: useradd test 指定密码:passwd test 但是有时候我们需要使用test运行执行一些root用户才有 ...

  6. 初探ASP.NET Web API

    什么是ASP.NET Web API? 官方的解释是 ASP.NET Web API is a framework that makes it easy to build HTTP services ...

  7. EF CodeFirst下数据库更新

    用EF Code first模式来开发系统,可使用Migrations命令来让数据库自动更新 1.在VS->工具->库程序包管理器->程序包管理控制台 中执行 Enable-Migr ...

  8. java 抽象(abstract) 构造 静态(static) 总结--2017-03-02

    抽象类:不能实例化!子类继承抽象类, 实例化子类对象才可以调用, 多态的体现; 抽象方法:必须被重写才能被调用; 静态方法:类名直接调用,或者实例化对象调用; 构造方法:new后面的括号里面带参数,就 ...

  9. recyclerview item点击事件

    recyclerview早就不陌生了,比起过去传统的listView,样式更多,也较为高效一点,这里整理一下recylerview中item的点击事件. recyclerview和listView不同 ...

  10. ios的300ms点击延时问题

    一.什么是ios的300ms点击延时问题 ios的移动端页面对点击事件有300ms延时. 二.为什么存在这个问题 这要追溯至 2007 年初.苹果公司在发布首款 iPhone 前夕,遇到一个问题 —— ...