一、前言

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

二、信号槽

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

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

 #include "slottest.h"
#include <QtWidgets/QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv); QPushButton button("Quit");
QObject::connect(&button,&QPushButton::clicked,&QApplication::quit);
button.show();
//slottest w;
//w.show();
return a.exec();
}

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

 /*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.

 You must use the SIGNAL() and SLOT() macros when specifying the signal and the method*/
QMetaObject::Connection connect(const QObject *, const char *,
const QObject *, const char *,
Qt::ConnectionType); QMetaObject::Connection connect(const QObject *, const QMetaMethod &,
const QObject *, const QMetaMethod &,
Qt::ConnectionType); QMetaObject::Connection connect(const QObject *, const char *,
const char *,
Qt::ConnectionType) const; QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
const QObject *, PointerToMemberFunction,
Qt::ConnectionType) QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
Functor);

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

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

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

 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在我的编译器中必须要将其分开,不然就会报错。

 #include<QObject>

 /////////////////newspaper.h
class Newsspaper :public QObject{ Q_OBJECT
public:
Newsspaper(const QString& name) :m_name(name)
{ }
void send();
signals:
void newPaper(const QString& name);
private:
QString m_name;
};

Newspaper.h

 #include "newspaper.h"

 void Newsspaper::send()
{
emit newPaper(m_name);
}

newspaper.cpp

 #include<QObject>
#include<QDebug> class Reader :public QObject
{
Q_OBJECT
public:
Reader();
void receiveNewspaper(const QString& name);
};

reader.h

 #include "reader.h"

 Reader::Reader(){}

 void Reader::receiveNewspaper(const QString& name)
{
qDebug() << "Receive Newspaper:" << name;
}

reader.cpp

 #include "slottest.h"
#include <QtWidgets/QApplication>
#include <QPushButton>
#include <QObject>
#include <QCoreapplication>
#include "newspaper.h"
#include "reader.h" int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Newsspaper newspaper("NewsPaper A");
Reader reader;
QObject::connect(&newspaper,&Newsspaper::newPaper,&reader,&Reader::receiveNewspaper);
newspaper.send(); return a.exec(); }

main.cpp

运行结果:

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. Django,ajax实现表格增删查改,Django内置分页功能。

    1.工程目录 2.urls.py """Django_ajax URL Configuration The `urlpatterns` list routes URLs ...

  2. 解决Cannot read property 'style' of null中样式问题

    <script type="text/javascript"> function updateTime(){ var timeNow = new Date(); var ...

  3. drupal7 jquery脚本忽然不运行

    jquery脚本经过调试,确认没有错误,但是最最近一次,调整了引入的次序,目的是方便我识别哪些js是我自己写的,哪些是前端给的,便于后期维护时,迅速找到自己写的部分. 调整引入次序前: 调整后(调整后 ...

  4. drupal 通过hook_menu实现添加菜单

    $items['mypayment/onlinepay']=array( 'title' => '在线充值', 'description' => '在线充值', 'page callbac ...

  5. Oql实体转自定义对象

    返回单体: GroupEnvironmentDTO 是自定义的一个DTO, GroupEnvironmentEntity.MapToPOCO(dto);  把上述查出来的对象转换为DTO 返回实体集合 ...

  6. Python爬虫教程-00-写在前面

    鉴于好多人想学Python爬虫,缺没有简单易学的教程,我将在CSDN和大家分享Python爬虫的学习笔记,不定期更新 基础要求 Python 基础知识 Python 的基础知识,大家可以去菜鸟教程进行 ...

  7. linux下部署redis

    基础知识: 1.Redis的数据类型: 字符串.列表(lists).集合(sets).有序集合(sorts sets).哈希表(hashs)2.Redis和memcache相比的独特之处: (1)re ...

  8. August 08th 2017 Week 32nd Tuesday

    The very essence of romance is uncertainty. 浪漫的精髓就在于它充满种种可能. Romance is the glamour that can turn th ...

  9. linux下的线程学习(一)

    线程标识 #include<pthread.h> int pthread_equal(    //用于比较两个线程是否相等 pthread_t tid1, //线程id=tid1 pthr ...

  10. [日常] NOIWC2019 冬眠记

    NOIWC 2019 冬眠记 辣鸡rvalue天天写意识流流水账 Day 0 早上没有跑操(极度舒服.png) 和春哥在博客颓图的时候突然被来送笔电的老爹查水表(捂脸) 母上大人骗我说这功能机不能放存 ...