一、前言

  前面说了Qt最基本的实例创建、控件以及工具集的介绍,相当于对于Qt有了一个初次的认识,这次我们开始认识Qt信号通信的重点之一——信号槽。

二、信号槽

  信号槽是 Qt 框架引以为豪的机制之一。熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力。

  所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。)

  1. #include "slottest.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QPushButton>
  4. int main(int argc, char *argv[])
  5. {
  6. QApplication a(argc, argv);
  7.  
  8. QPushButton button("Quit");
  9. QObject::connect(&button,&QPushButton::clicked,&QApplication::quit);
  10. button.show();
  11. //slottest w;
  12. //w.show();
  13. return a.exec();
  14. }

  我们开始一步一步的分析这短短的几行代码。第6行声明一个QApplication类的对象,用于程序的启动和调用;第8行声明了一个按钮控件QPushButton类的对象,用于产生一个按钮,并传递一个字符串“Quit”命名控件显示的名称;第9行用到了QObject中的connect函数,我们先来看这个函数的定义。

  1. /*Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns a handle to the connection that can be used to disconnect it later.
  2.  
  3. You must use the SIGNAL() and SLOT() macros when specifying the signal and the method*/
  4. QMetaObject::Connection connect(const QObject *, const char *,
  5. const QObject *, const char *,
  6. Qt::ConnectionType);
  7.  
  8. QMetaObject::Connection connect(const QObject *, const QMetaMethod &,
  9. const QObject *, const QMetaMethod &,
  10. Qt::ConnectionType);
  11.  
  12. QMetaObject::Connection connect(const QObject *, const char *,
  13. const char *,
  14. Qt::ConnectionType) const;
  15.  
  16. QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
  17. const QObject *, PointerToMemberFunction,
  18. Qt::ConnectionType)
  19.  
  20. QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
  21. Functor);

  从上面可以看到,connect函数一共有五个重载的版本,其中各个参数比较之后sender和receiver没有什么区别,都是QObject指针,主要是signal和slot形式的区别。再回到我们的调用回来,我们采用的是第五个重载,当我们的Button发出了clicked信号时,会调用QApplication的quit函数,从而使程序退出。

  对于信号和槽的要求是参数保持一致,这里所说的一致是参数类型的一致。如果不一致,可以是槽函数的参数可以比信号的少,而且参数的顺序必须保持一致。

  将上述代码稍加修改,使用lambda表达式后我们再来看一下效果。

  1. QObject::connect(&button, &QPushButton::clicked,/*&QApplication::quit*/[](){qDebug()<< "quit"; });

三、QWidget、QDialog及QMainWindow的区别

  QWidget类是所有用户界面对象的基类。 窗口部件是用户界面的一个基本单元:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己。每一个窗口部件都是矩形的,并且它们按Z轴顺序排列。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。

  QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围 菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态条变得更容易,当用户点击菜单项或者工具条按钮时,槽会被调用。

  QDialog类是对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模态对话框也可以是非模态对话框。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。

  QDialog 是最普通的顶级窗口。一个不会被嵌入到父窗口部件的窗口部件叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰。)在Qt中,QMainWindow和不同的QDialog的子类是最普通的顶级窗口。

  如果是顶级对话框,那就基于QDialog创建,如果是主窗体,那就基于QMainWindow,如果不确定,或者有可能作为顶级窗体,或有可能嵌入到其他窗体中,则基于QWidget创建。
  当然了,实际中,你还可以基于任何其他部件类来派生。看实际需求了,比如QFrame、QStackedWidget等等。

四、自定义信号槽

  通过系统提供的connect函数可以让我们连接系统信号和槽,但是你应该会想到我们桐乡可以自己定制自己的信号槽,这也是Qt架构的设计思路,用于我们设计解耦的程序。信号槽不是GUI模块提供的,而是Qt核心特性之一,所以我们同样可以在普通的控制台程序中使用信号槽。

  注意:我之所以将头文件和源文件分开来写,是因为moc在我的编译器中必须要将其分开,不然就会报错。

  1. #include<QObject>
  2.  
  3. /////////////////newspaper.h
  4. class Newsspaper :public QObject{
  5.  
  6. Q_OBJECT
  7. public:
  8. Newsspaper(const QString& name) :m_name(name)
  9. {
  10.  
  11. }
  12. void send();
  13. signals:
  14. void newPaper(const QString& name);
  15. private:
  16. QString m_name;
  17. };

Newspaper.h

  1. #include "newspaper.h"
  2.  
  3. void Newsspaper::send()
  4. {
  5. emit newPaper(m_name);
  6. }

newspaper.cpp

  1. #include<QObject>
  2. #include<QDebug>
  3.  
  4. class Reader :public QObject
  5. {
  6. Q_OBJECT
  7. public:
  8. Reader();
  9. void receiveNewspaper(const QString& name);
  10. };

reader.h

  1. #include "reader.h"
  2.  
  3. Reader::Reader(){}
  4.  
  5. void Reader::receiveNewspaper(const QString& name)
  6. {
  7. qDebug() << "Receive Newspaper:" << name;
  8. }

reader.cpp

  1. #include "slottest.h"
  2. #include <QtWidgets/QApplication>
  3. #include <QPushButton>
  4. #include <QObject>
  5. #include <QCoreapplication>
  6. #include "newspaper.h"
  7. #include "reader.h"
  8.  
  9. int main(int argc, char *argv[])
  10. {
  11. QApplication a(argc, argv);
  12. Newsspaper newspaper("NewsPaper A");
  13. Reader reader;
  14. QObject::connect(&newspaper,&Newsspaper::newPaper,&reader,&Reader::receiveNewspaper);
  15. newspaper.send();
  16.  
  17. return a.exec();
  18.  
  19. }

main.cpp

运行结果:

  1. Receive Newspaper: "NewsPaper A"

  根据代码我们对几个重点进行解释:1、Q_OBJECT是Qt的一个宏,能够使程序具有信号槽机制,由moc进行处理,会生成以moc为开头的文件,moc是一种预处理器;2、emit是Qt的另一个宏,用于表示发射信号,使槽函数能够接受信号;3、使用connect函数进行信号槽的连接,槽函数在获取到消息体和信号参数后做出相应,这里就是响应打印消息。4、信号槽的机制类似于广播,可以参照广播模式来理解代码。5、使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;6、槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响。

  感谢你的耐心阅读,如果有哪些地方错误,请提出来,谢谢!

我的QT5学习之路(四)——信号槽的更多相关文章

  1. Qt 学习之路 :信号槽

    信号槽是 Qt 框架引以为豪的机制之一.熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被 ...

  2. 我的QT5学习之路(目录)

    说明:本目录内容为自己学习的心得和记录,参考资料来源于网络,学习过程中多方汲取,如有错误,欢迎指正和批评. Qt开发相关文章目录 一.我的Qt学习之路系列 1.[笔记]我的Qt学习之路(一)——浅谈Q ...

  3. 我的QT5学习之路(一)——浅谈QT的安装和配置

    一.前言 说到Qt,不能不说到C++,这门伟大的语言.因为其面向对象的编程思想和陡峭的学习曲线,一开始学习起来很是吃力.Qt从QT4开始基本封装了很多C++的工具库和界面库,而且支持跨平台,这是它最大 ...

  4. Redis——学习之路四(初识主从配置)

    首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务 ...

  5. QT学习之深入了解信号槽

    槽函数和普通的 C++成员函数没有很大的区别.它们也可以使 virtual 的:可以被重写:可以使 public.protected 或者 private 的:可以由其它的 C++函数调用:参数可以是 ...

  6. QT学习记录之理解信号槽机制

    作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...

  7. 我的QT5学习之路(三)——模板库、工具类和控件(下)

    一.前言 作为第三篇的最后一部分,我们来看一下Qt的控件,谈到控件,就会让人想到界面的美观性和易操作性,进而想到开发的便捷性.作为windows界面开发的MFC曾经是盛行了多少年,但是其弊端也随着其他 ...

  8. zigbee学习之路(四):按键控制(中断方式)

    一.前言 通过上次的学习,我们学习了如何用按键控制led,但是在实际应用中,这种查询方式占用了cpu的时间,如果通过中断控制就可以解决这个问题,我们今天就来学习按键控制的中断方式. 二.原理分析 传统 ...

  9. [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. 多线程拷贝备份文件方法(Windows)

    D:\bat\robocopy.exe D:\backupdata  \\192.168.36.45\BData\  db_20170716.dmp 解释: 微软提供的robocopy.exe命令,默 ...

  2. 关于iFrame特性总计和iFrame跨域解决办法

    1.iframe 定义和用法 iframe 元素会创建包含另外一个文档的内联框架(即行内框架). HTML 与 XHTML 之间的差异 在 HTML 4.1 Strict DTD 和 XHTML 1. ...

  3. NGINX本地服务器解析域名

    1.找到hosts文件 ,添加需要解析的域名 2.在cmd命令窗口中检测解析是否生效 3 找到本地服务器的域名配置文件:添加绑定的域名,更改访问的目录 4.添加pathinfo.隐藏index.php ...

  4. 跨域方法:JSONP、iframe

    同源策略:浏览器出于安全考虑,会限制文档或脚本中发起的跨域请求(但src请求不受此限)资源的加载.实际上通过抓包软件可以发现请求和响应都会成功,但是响应数据并不会被浏览器加载.不同源的客户端脚本(ja ...

  5. UIResponder NSSet UITouch UIEvent

    UIResponder: UIView的超类,用来响应handle(触屏.motion.响应者等)事件. NSSet:一系列的类集合(类似数组). UITouch:一个点击类.负责:点击的view,w ...

  6. 菜单Menu(AS开发实战第四章学习笔记)

    4.5 菜单Menu Android的菜单主要分两种,一种是选项菜单OptionMenu,通过按菜单键或点击事件触发,另一种是上下文菜单ContextMenu,通过长按事件触发.页面的布局文件放在re ...

  7. fiddler抓包出现Tunnel to

    在抓包的时候,有时候会遇到很多的tunnel to,图标是一把锁的形状,如下图: connect是为了建立http tunnel,connect是http众多方法中的其中一种,它跟post.get.p ...

  8. 一些baidu面经

    百度问的一些问题供参考: 1. epoll 和 select,epoll 两种模式,阻塞非阻塞: 2. 两个严格递增链表找出相同的元素组成新的链表: ref1   ref 3. 网络传输中如何传送一个 ...

  9. visio 修改画布大小

    按住Ctrl,鼠标移到画布边缘,拖拉即可.

  10. Homebrew 安装 MySQL

    安装 Homebrew brew doctor 确认 brew 在正常工作 brew update 更新包 brew install mysql 安装 MySQL ​ ==> Downloadi ...