QT学习(二)
这一篇学习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学习(二)的更多相关文章
- qt学习(二) buttong layout spinbox slider 示例
开启qt5 creator 新建项目 qt widgets 改写main.cpp #include "mainwindow.h" #include <QApplication ...
- QT学习二:工具栏
QT 的工具栏提供 Dock 功能.文字/图标显示排列的功能. void MainWindow::createToolBar(void) { QToolBar *toolBar = new QToo ...
- QT学习第1天
QT学习第一天 坚持住!! 一 Qt概述 1.Qt发展历史 (1)1991年诞生(Haavard Nord/Eirik Chambe-Eng), (2)1994年创立Troll Tech(奇趣科技) ...
- Qt 学习之路 2(56):使用模型操作数据库
Qt 学习之路 2(56):使用模型操作数据库 (okgogo: skip) 豆子 2013年6月20日 Qt 学习之路 2 13条评论 前一章我们使用 SQL 语句完成了对数据库的常规操作,包括简单 ...
- Qt 学习之路 2(49):自定义只读模型
Qt 学习之路 2(49):自定义只读模型 豆子 2013年5月5日 Qt 学习之路 2 18条评论 model/view 模型将数据与视图分割开来,也就是说,我们可以为不同的视图,QListView ...
- Qt 学习之路 2(45):模型
Home / Qt 学习之路 2 / Qt 学习之路 2(45):模型 Qt 学习之路 2(45):模型 豆子 2013年2月26日 Qt 学习之路 2 23条评论 在前面两章的基础之上,我们 ...
- Qt 学习之路 2(44):QFileSystemModel
Home / Qt 学习之路 2 / Qt 学习之路 2(44):QFileSystemModel Qt 学习之路 2(44):QFileSystemModel 豆子 2013年2月21日 Qt ...
- Qt 学习之路 2(29):绘制设备
Qt 学习之路 2(29):绘制设备 豆子 2012年12月3日 Qt 学习之路 2 28条评论 绘图设备是继承QPainterDevice的类.QPaintDevice就是能够进行绘制的类,也就是说 ...
- Qt学习笔记-Widget布局管理
Qt学习笔记4-Widget布局管理 以<C++ GUI Programming with Qt 4, Second Edition>为参考 实例:查找对话框 包含三个文件,f ...
随机推荐
- Linux定时任务--Crond使用教程
Linux定时任务--Crond使用教程 1. 介绍Crond crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后 ...
- docker的平替--podman
前言 我们都知道,docker这个东西,是CaaS(Container as a Service,容器即服务)的通常解法.我们使用docker来管理容器的生命周期,比如镜像的生成.容器的管理和定制(D ...
- HiEngine:可媲美本地的云原生内存数据库引擎
摘要:HiEngine与华为GaussDB (for MySQL)集成,将内存数据库引擎的优势带到云端,并与基于磁盘的引擎共存.HiEngine的性能比传统的以存储为中心的解决方案高出7.5倍. 本文 ...
- 【ArcGIS教程】专题图制作-人口密度分布图——人口密度分析
本篇以湖北省为例,制作人口密度分布图:这里所使用的为湖北省的省.市.县三个级别的行政区划矢量数据,以及居民点数据,进而进行密度分析. 示例数据来源于地理遥感生态网,网站地址www.gisrs.c ...
- Redis 内存优化神技,小内存保存大数据
大家好,我是「码哥」,大家可以叫我靓仔. 这次码哥跟大家分享一些优化神技,当你面试或者工作中你遇到如下问题,那就使出今天学到的绝招,一招定乾坤! 如何用更少的内存保存更多的数据? 我们应该从 Redi ...
- Educational Codeforces Round 132 (C,D) 题解 cf#1709
昨晚打了这把EDU,赛后看了dalao们的C题代码豁然开朗恍然大悟 实在是太巧妙了 这场来说,D题的通过率比C题高太多了(估计很多人都在C题卡了然后没做D 先放题目链接 题目链接 C - Recove ...
- Acwing八数码
此题用\(bfs\) 首先我们可以定义两个重要的数组 \(unordered\_map<string,int> d\)表示\(string\)距离\(start\)的交换次数 \(queu ...
- GDOI 2022 普及组游记
To LuoguDAY -1 期中考成绩下来了,全无了除了历史 (96) 和生物 (95) 还能看,剩下的-,语文 101.5 ,少错一道选择和断句就 107.5 了,居然比雌兔还低 数学少错一道选择 ...
- 第十六天python3 文件IO(二)
BytesIO操作 io模块中的类 from io import BytesIO 内存中,开辟的一个二进制模式的buffer,可以像文件对象一样操作它: 当close方法被调用的时候,这个buffer ...
- 洛谷 P5627 题解
题意 Link 求 \[\sum_{i=1}^{2^n}\log_2\left(\prod_{j=1}^i\operatorname{lowbit}(j)\right) \] \(n\le 2^{64 ...