信号槽

信号槽是QT中用于对象间通信的一种机制,也是QT的核心机制。在GUI编程中,我们经常需要在改变一个组件的同时,通知另一个组件做出响应。例如:

一开始我们的Find按钮是未激活的,用户输入要查找的内容后,查找按钮就被激活,这就是输入框与Find按钮这两个组件间通信的例子。

早期,对象间的通信采用回调来实现。回调实际上是利用函数指针来实现,当我们希望某件事发生时处理函数能够获得通知,就需要将回调函数的指针传递给处理函数,这样处理函数就会在合适的时候调用回调函数。回调有两个明显的缺点:

  • 它们不是类型安全的,我们无法保证处理函数传递给回调函数的参数都是正确的。
  • 回调函数和处理函数紧密耦合,源于处理函数必须知道哪一个函数被回调。

信号与槽

在QT中,我们有回调技术之外的选择,也即是信号槽机制。所谓的信号与槽,其实都是函数。当特定事件被触发时(如在输入框输入了字符)将发送一个信号,而与该信号建立的连接槽,则可以接收到该信号并做出反应(激活Find按钮)。

QT组件预定义了很多信号和槽,而在GUI编程中,我们习惯于继承那些组件,继承后添加我们自己的槽,以便以我们的方式来处理信号。槽和普通的C++成员函数几乎是一样的,它可以是虚函数,可以被重载,可以是共有、私有或是保护的,也同样可以被其他成员函数调用。它的函数参数也可以是任意类型的。唯一不同的是:槽还可以和信号连接在一起。

与回调不同,信号槽机制是类型安全的。这体现在信号的函数签名与槽的函数签名必须匹配上,才能够发生信号的传递。实际上,槽的参数个数可以比信号的参数个数少,因为槽能够忽略信号形参中多出来的参数。信号和槽是松耦合的:发出信号的类不关心哪些类将接收它的信号。QT的信号槽机制吧哦这里在正确的时间,槽能够接收到信号的参数并调用。信号和槽都可以有任意个数的参数,它们都是类型安全的。

自定义信号和槽的一个例子

首先我们要知道的是,所有继承自QObject或者它的子类(如QWidget)都可以包含信号槽。我们写的类须继承自QObject(或其子类)。所有包含了信号槽的类都必须在声明的上部含有Q_OBJECT宏。

一个基于QObject的C++简单类:

//MyStr.h
# ifndef MYSTR
# define MYSTR
#include<QObject>
#include<QString> class MyStr :public QObject
{
Q_OBJECT //必须包含的宏 public:
MyStr (){m_value = "zero";} QString value() const {return m_value;} public slots :
void setValue(QString value ); signals: //信号
void valueChanged(QString newValue);
private:
QString m_value;
}; #endif
  • 在这个简单的类中,我们可以看到,使用slots来表示槽,而使用signals来表示信号。实际上没有那么神秘,它们都是宏定义,甚至signals只是public的宏定义:
#     define signals public
  • Signal的代码会由 moc 自动生成,开发人员一定不能在自己的C++代码中实现它。

  • 反之,槽应该由编程人员来实现,下面提供MyStr::setVaule()的一种可能实现

#include"MyStr.h"
void MyStr::setValue(QString value)
{
if(value != m_value)
{
m_value = value;
emit valueChanged(value);
}
}

setValue函数首先比较新参的值与数据成员的值是否是一样的(后面有解释为何这样做),如果不是,则设置好数据成员m_value的值,然后,把信号valueChanged()发送出去。发送给谁?类并没有写,这并不是类设计者所关心的,也不是类所关心的,它只管把信号发送出去就行。然后,我们再来设置谁来接收这个信号。

int main(int argc, char *argv[])
{
MyStr a;
MyStr b;
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SLOT(setValue(QString)));
a.setValue("this is A");
return 0;
}

我们定义了两个类对象a/b,使用 QObject::connect()函数指定了发送方、信号、接收方、槽等信息,connect函数的格式如下:

 QObject::connect(    发送方,    SIGNAL(...),    接收方,    SLOT(..)    );

当我们调用a的成员函数setValue时,该函数除了把a.m_value设置为"this is A",也把信号valueChanged()发送出去,被b.setValue所接收,从而,把b.m_value设置为"this is A",同时b.setValue又把valueChanged信号发射出去,然而该信号并没有对象接收,因为我们没有建立以b为发送方的任何连接。此时你应该明白,为何在emit前需要判断value != m_value,因为如果没有此步骤,且恰巧设置了

QObject::connect(&b,SIGNAL(valueChanged(QString)),&a,SLOT(setValue(QString)));

则b的信号被a接收,a又发送信号被b接收,如此进入死循环。

int main(int argc, char *argv[])
{
QApplication app(argc, argv); MyStr a;
MyStr b;
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SLOT(setValue(QString)));
a.setValue("this is A"); QLabel* label = new QLabel;
label->setText( b.value());
label->show();
return app.exec();
}

我们使用label输出来看看b是否接收到a的信号,如果是,则b的内容应该是"this is A",输出在label上,程序运行结果:

这个例子展示了对象之间通信的一种方式。对象间可以一起工作,而不需要知道彼此的任何信息。为了达到通信的目的,只需要将它们连接起来,而这只需要通过 调用 QObject::connect() 函数指定一些简单信息就好。

细节

连接

要把信号成功连接到槽,它们的参数必须具有相同的顺序和相同的类型,或者允许信号的参数比槽多,槽会自动忽略掉多出来的参数而进行调用。

一个信号可以连接多个槽

使用QObject::connect可以把一个信号连接到多个槽,而当信号发射时,将按声明联系时的顺序依次调用槽。

 MyStr  a;
MyStr b;
MyStr c;
//信号连接到两个槽
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SLOT(setValue(QString)));
QObject::connect(&a,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
a.setValue("this is A");
//依次调用b.setValue()、c.setValue()

多个信号可以连接同一个槽

同样的,可以让多个信号连接到同一个槽上 ,而且其中的每一个信号的发送,都会调用了那个槽。

 MyStr  a;
MyStr b;
MyStr c;
//两个信号连接到同一个槽
QObject::connect(&a,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
QObject::connect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
//下面的操作皆会调用到槽c.setValue()
a.setValue("this is A");
b.setValue("this is B");

一个信号可以和另外一个信号相连接

当发射第一个信号的时候,也会把第二个信号一个发送出去。

 MyStr  a;
MyStr b;
MyStr c;
//两个信号相连接
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SIGNAL(valueChanged(QString)));
//再建立b与c的连接
QObject::connect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
//下面的操作同时发送了信号a.valueChanged与b.valueChanged
a.setValue("this is A");
//从而信号b.valueChanged被槽c.setValue所接收

连接可以被移除

//移除b 与 c之间的连接
QObject::disconnect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));

实际上当对象被delete时,其关联的所有链接都会失效,QT会自动移除和这个对象的所有链接。

感谢您耐心的阅读。

QT信号槽机制的更多相关文章

  1. QT源码之Qt信号槽机制与事件机制的联系

    QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...

  2. Qt信号槽机制理解

    1. 信号和槽概述 > 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式(发布-订阅模式).当某个`事件`发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(s ...

  3. Qt信号槽机制的实现(面试的感悟,猜测每一个类保存的一个信号和槽的二维表,实际使用函数指针 元对象 还有类型安全的检查设定等等)

    因为面试时问了我这道题,导致我想去了解信号槽到底是如何实现的,于是贴着顺序看了下源码,大致了解了整个框架.网上关于信号槽的文章也很多,但是大部分都是将如何应用的,这里我就写一下我所理解的如何实现吧, ...

  4. Qt信号槽-原理分析

    目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...

  5. C++11实现Qt的信号槽机制

    概述 Qt的信号槽机制是Qt的核心机制,按钮点击的响应.线程间通信等都是通过信号槽来实现的,boost里也有信号槽,但和Qt提供的使用接口很不一样,本文主要是用C++11来实现一个简单的信号槽,该信号 ...

  6. VJGUI消息设计-兼谈MFC、QT和信号/槽机制

    星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...

  7. Qt学习记录--02 Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)

    一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说:一切皆消息.它可以很方便实现不同窗体之间的通信,然而MFC库将很多底层的消息都屏蔽了,尽管使用户更加方便.简易地处理消息,但 ...

  8. Qt开发之信号槽机制

    一.信号槽机制原理 1.如何声明信号槽 Qt头文件中一段的简化版: class Example: public QObject { Q_OBJECT signals: void customSigna ...

  9. QT写hello world 以及信号槽机制

    QT是一个C++的库,不仅仅有GUI的库.首先写一个hello world吧.敲代码,从hello world 写起. #include<QtGui/QApplication> #incl ...

随机推荐

  1. 关于Kendo UI的使用心得

    1.在筛选里面的条件选项进行编辑 filterable: { extra: false, operators: { string: { startswith: "Starts with&qu ...

  2. 10 Things Every Java Programmer Should Know about String

    String in Java is very special class and most frequently used class as well. There are lot many thin ...

  3. ubuntu Apache 2命令

    Task: Start Apache 2 Server /启动apache服务# /etc/init.d/apache2 startor$ sudo /etc/init.d/apache2 start ...

  4. poj1190

    生日蛋糕 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 18230 Accepted: 6491 Description 7月1 ...

  5. java多线程系类:基础篇:08之join

    本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_40)3. join()示例 转载请注明出处:http:// ...

  6. 认识HTML5的WebSocket

    在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocket API.WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术.这个新的API提供了一个方法 ...

  7. 资源搜集:Git精品文章推荐,常年更新

    以下放置的是搜集到的Git精品文章,常年更新: Git 常用命令详解(二) Git版本控制软件结合GitHub从入门到精通常用命令学习手册 Pro Git(中文版)

  8. 熟悉css/css3颜色属性

    颜色属性无处不在.字体要用颜色,背景可以有颜色,粒子特效更是离不开颜色.本文参考了一些资料简单总结下以备日后查阅. css中颜色的定义方式: 十六进制色 RGB & RGBA HSL & ...

  9. [PGM] I-map和D-separation

    之前在概率图模型对概率图模型做了简要的介绍.此处介绍有向图模型中几个常常提到的概念,之前参考的多为英文资料,本文参考的是<概率图模型-原理与技术的>中译版本.很新的书,纸质很好,翻译没有很 ...

  10. Android Stduio统计项目的代码行数

    android studio统计项目的代码行数的步骤如下: 1)按住Ctrl+Shift+A,在弹出的框输入‘find’,然后选择Find in Path.(或者使用快捷键Ctrl+Shift+F) ...