这一篇学习QT中最重要的也是最有特色的信号槽机制。

(因为我学习过MFC,所以我觉得QT的信号槽机制和MFC中的消息响应机制是一一对应的。不过是MFC用的是宏来实现,而QT用的是消息和槽。相对来说QT可能会更灵活一点,但是也更容易出错

QT学习(二)

首先应该明白为什么要去用信号和槽,它是为了实现什么而存在的。

因为QT是GUI编程,GUI编程最关注的就是用户和应用程序的交互(通过将某种用户事件
(比如按下鼠标)与程序事件(比如退出程序)联系起来,使用户能够在图形界面中只使用鼠标来控制程序。)

其他的程序使用回调函数来处理这类问题的(其他不是所有)

(所谓的回调函数是指:按照一定的形式由开发人员定义并编写实现内
容。使用回调函数,实际上就是在调用某个函数(通常是API函数)时,将自
己的一个函数(也就是回调函数)的地址作为参数传递给那个函数。而那个
函数在需要的时候,也就是某种事情发生的时候,利用传递的函数地址调
用回调函数,这时开发人员可以利用这个机会在回调函数中处理消息或完
成一定的操作。然而会点函数十分的复杂不容易理解,所以就有了信号和槽)

信号和槽是为了实现对象与对象之间(跨越类的!!!!)通信而存在的,然而面向对象程序中就是将应用程序对象化,所以这种机制就能够实现用户事件和程序事件的交互。

Qt的窗口部件有很多预定义的槽,当一个特定事件发生的时候,一个信号被发射,对信号感兴趣的槽就会调用对应的响应函数。

在QObject类或者其一个子类(比如:QWidget类)继承的所有类中,都存在了信号和槽。当对象改变其状态的时候,信号被发送,对象不关心有没有其他对象接收到这个信号。槽是类的正常成员函数,可以将信号和槽通过connect()函数任意连接。当一个信号被发射,它所连接的槽会被立即执行,如同一个普通函数调用一样。

当信号被发出时,会调用与之相连接的槽。槽是普通的C++函数,可以用普通的方式来调用。它唯一特殊的地方在于可以与信号相连接。槽的参数不能有默认值。同样,信号的参数也不能有默认值。在槽的参数中尽量不使用自定义的数据类型,因为这样将会使通用性降低。

public slot: 任何信号都可以与之相连接。这在窗口部件编程中非常有用,用于创建一些对彼此一无所知的对象,只有                   通过信号和槽来交换信息。public slot就像是标准的铁路一样。
protected slot: 只有该类及其子类所派生的对象的信号才可以与之相接。这类槽的目的通常是为了类的完善,而不是类与外界的接口。
private slot: 只有该类自己的信号才可以与之相连接。

信号和槽是相当高效的。当然,它们与“实时”的回调函数相比,在增加了灵活性的同时也损失了一些速度,正所谓有利必有弊,但是这种速度的损失相当微不足道。因此,信号/槽机制具有的简便性和灵活性的特性,使用信号和槽是用户交互的必然选择
信号
当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。只有定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被立刻执行,就象一个正常的函数调用一样。信号-槽机制完全独立于任何GUI事件循环。只有当所有的槽返回以后发射函数(emit)才返回。如果存在多个槽与某个信号相联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪个后执行。

需要注意的事项:

1 多重继承把QObject的子类作为第一个父类
class SomeClass : public QObject, public OtherClass
{
……
}
2 函数指针不能作为信号和槽的参数,在你考虑使用函数指针作为信号/槽的参数的时候,继承是一个不错的
替代方法
3 不能把友元声明friend放在信号或者槽的声明部分
4 把继承的成员函数升级为公有状态,这个C++特征对信号和槽并不适

5 因为元对象编辑器不能展开#define,所以,在信号和槽中类型宏作为
一个参数不能工作
6 构造函数不能用于信号部分和槽部分
7 属性的声明应该放在含有相应的读写函数的公有部分之前

槽和信号的具体使用方法:

在类定义的第一行加入Q_OBJECT宏。类中的其他项都需要一个分号
终止符,而Q_OBJECT宏却不需要,但如果喜欢,也可以加上分号(是因
为编译器在处理时根本不考虑分号)。我们可以按照以下方式定义一个类:
class SenderClass
{
Q_OBJECT
……
值得注意的是:在一个类中可以定义任意个槽和信号,但是Q_OBJECT只需要一次。向类定义中加入信号的原型。比如:如果信号将要发送一个字符串作为该信号的参数,那么原型大概以如下的方式去编写:
……
signals:
void newName(QString &name);

使用发送语句来调用所有监听这个信号的方法。这一步使用的语法和用来调用一个局部方法的语法是一样的,只不过这时用emit关键字开头:
QString name;
emit newName(name);

与信号一样,槽需要在类定义的上部加入Q_OBJECT宏:
class ReceiverClass
{
Q_OBJECT
……
向类定义中加入槽方法的原型。这个原型必须与它将要接收的信号一样(也就是说,具有同样的一套参数)。由于槽是方法,所以,在作为槽使用的同时,也可以被直接调用。槽的方法可以设置成为公有的属性。
public slots:
void nameChanged(QString &name);

注:编写代码创建将要发送信号的类的实例。只有这个实例的存在,才能把槽和信号联系在一起。把槽和信号连接起来。这个工作通常在构造函数中完成,但是如果这个对象构造得比较晚,那么连接工作也可以晚点做。调用connect()方法把你的槽加入到方法列表中,每当指定的信号发出的时候,这个方法就会被调用。

必须小心不要创建死循环。如果一个槽方法发送一个信号,此信号直接或者间接地执行了发送一个信号的方法,而这个信号又被最开始的槽所接收,那么信号将连续不断的调用槽,你编写的程序就会崩溃。比如:如果名为firstfun()的方法发送了一个A信号,A信号被second()槽所接收,而second()槽发送了信号B,最后,名为firstfun()的方法接收了信号B,这样就产生了一个死循环。这种循环将一直执行,直到该程序崩溃为止(或者用户进入长时间的等待)。还需要小心槽和信号方法在连接语句中的参数是否匹配。当程序运行的时候,直到试着去解决一个问题时,才可能得到出错的信息。为了避免这个问题的出现,必须确定每次增加内容的时候,都要进行测试,或者改变槽和信号部分。唯一的出错信息是当connect()方法找不到匹配对象的时候,输出一个写入控制台上的字符串。此后,程序就忽略了这个信号的存在。只有从命令行运行程序的时候,才能够看到控制台输出的信息。
connect(sender,SIGNAL(newName(QString &)),this,
SLOT(nameChanged(QString &)));
注:前两个参数指定信号的来源,后两个参数指定目标槽。宏SIGNAL()和SLOT()都需要完整的方法原型,原型必须遵循,用来调用一种方法的参数必须和该种方法可以使用的参数保持一致。无论任何使用emit发送信号,就好象是你编写的程序直接调用每一个槽方法一样。也就是说,直到槽方法返回,你编写的程序才能继续执行。因此,通常应当保持在槽方法内部的处理过程中尽可能的简单,这样才不会因此中止信号的发送。发送信号的可能是用户接口过程,操作过程表现得比较慢或者缓慢。

到这里QT最重要的特性已经OK,剩下的就是试练,敬仰,从下一章开始!!

QT学习(二)的更多相关文章

  1. qt学习(二) buttong layout spinbox slider 示例

    开启qt5 creator 新建项目 qt widgets 改写main.cpp #include "mainwindow.h" #include <QApplication ...

  2. QT学习二:工具栏

    QT  的工具栏提供 Dock 功能.文字/图标显示排列的功能. void MainWindow::createToolBar(void) { QToolBar *toolBar = new QToo ...

  3. QT学习第1天

    QT学习第一天  坚持住!! 一 Qt概述 1.Qt发展历史 (1)1991年诞生(Haavard Nord/Eirik Chambe-Eng), (2)1994年创立Troll Tech(奇趣科技) ...

  4. Qt 学习之路 2(56):使用模型操作数据库

    Qt 学习之路 2(56):使用模型操作数据库 (okgogo: skip) 豆子 2013年6月20日 Qt 学习之路 2 13条评论 前一章我们使用 SQL 语句完成了对数据库的常规操作,包括简单 ...

  5. Qt 学习之路 2(49):自定义只读模型

    Qt 学习之路 2(49):自定义只读模型 豆子 2013年5月5日 Qt 学习之路 2 18条评论 model/view 模型将数据与视图分割开来,也就是说,我们可以为不同的视图,QListView ...

  6. Qt 学习之路 2(45):模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(45):模型 Qt 学习之路 2(45):模型  豆子  2013年2月26日  Qt 学习之路 2  23条评论 在前面两章的基础之上,我们 ...

  7. Qt 学习之路 2(44):QFileSystemModel

    Home / Qt 学习之路 2 / Qt 学习之路 2(44):QFileSystemModel Qt 学习之路 2(44):QFileSystemModel  豆子  2013年2月21日  Qt ...

  8. Qt 学习之路 2(29):绘制设备

    Qt 学习之路 2(29):绘制设备 豆子 2012年12月3日 Qt 学习之路 2 28条评论 绘图设备是继承QPainterDevice的类.QPaintDevice就是能够进行绘制的类,也就是说 ...

  9. Qt学习笔记-Widget布局管理

    Qt学习笔记4-Widget布局管理       以<C++ GUI Programming with Qt 4, Second Edition>为参考 实例:查找对话框 包含三个文件,f ...

随机推荐

  1. weiphp 插件"通用表单"BUG修改

    修改文件目录 在类FormsValueController 中添加函数 // 匹配函数 //$value:字符串 //$validate_rule:正则规则 // return true:比配成功,f ...

  2. 加班?不存在的啦~Python处理Excel,学会这十四个方法,工作量减少大半

    现在Python横行的年代,财务.人事.行政等等岗位多少得学点Python,省事又不费脑!所有操作都用Python自动实现, 加班?不存在的! excel和python其实都是工具,不要也不用拿去做对 ...

  3. 在linux上配置Maven环境变量

    1.首先下载maven ,这里我使用的是3.8.1 Maven – Download Apache Maven 2.在linux环境中,将maven上传至 /usr/local/目录中 这里我将mav ...

  4. NC24840 [USACO 2009 Mar S]Look Up

    NC24840 [USACO 2009 Mar S]Look Up 题目 题目描述 Farmer John's N (1 <= N <= 100,000) cows, convenient ...

  5. RASP | 远程Java应用的RASP调试教程

    远程Java应用的RASP调试教程 介绍 Java RASP是基于Java Agent技术实现的,而Java Agent代码无法独立启动,必须依赖于一个Java运行时程序才能运行. 如何调试一个Jav ...

  6. C++ delete后的指针在不同编译器下的状态差异

    今天看到小伙伴分享的一个问题,小伙伴用的MSVC2019编译器,在对delete后的指针进行取值操作时触发了访问冲突. #include<iostream> using namespace ...

  7. Graphics2D类

    Graphics2D类 Java语言在Graphics类提供绘制各种基本的几何图形的基础上,扩展Graphics类提供一个Graphics2D类,它拥用更强大的二维图形处理能力,提供.坐标转换.颜色管 ...

  8. java通过注解顺序通过映射导出excel

    import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.ann ...

  9. Solution -「2021.11.27」\Infty

    T1. 显然往 \(x < 0, y < 0\) 的点走一定不优. 根据转移式可发现 \(C(x, y)\) 即从 \((0, 0)\) 走到 \((x, y)\) 的方案数 \(\dbi ...

  10. 网格动物UVA1602

    题目大意 输入n,w,h(1<=n<=10,1<=w,h<=n).求能放在w*h网格里的不同的n连块的个数(平移,旋转,翻转算一种) 首先,方法上有两个,一是打表,dfs构造连 ...