Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法。作为一种通用的处理机制,信号与反应槽非常灵活,可以携带任意数量的参数,参数的类型也由用户自定。同时其本身也是类型安全的,任何一个从QObject或其子类继承的用户类都可以使用信号与反应槽。

信号的作用如同Windows系统中的消息。在Qt中,对于发出信号的对象来说,它并不知道是谁接收了这个信号。这样的设计可能在某些地方会有些不便,但却杜绝了紧耦合,于总体设计有利。反应槽是用来接收信号的, 但它实际上也是普通的函数,程序员可以象调用普通函数一样来调用反应槽。与信号类似的是,反应槽的拥有者也不知道是谁向它发出了信号。在程序设计过程中,多个信号可以连接至一个反应槽,类似的,一个信号也可以连接至多个反应槽,甚至一个信号可以连接至另一个信号。

在Windows中,如果我们需要多个菜单都激发一个函数,一般是先写一个共用函数,然后在每个菜单的事件中调用此函数。在Qt中如果要实现同样的功能,就可以把实现部分写在一个菜单中,然后把其他菜单与这个菜单级联起来。

虽然信号/反应槽机制有很多优点,使用也很方便,但它也不是没有缺点。最大的缺点在于要稍微牺牲一点性能。根据Trolltech公司的自测,在CPU为Intel PentiumII 500 Mhz的PC机上,对于一个信号对应一个反应槽的连接来说,一秒钟可以调用两百万次;对于一个信号对应两个反应槽的连接来说,一秒钟可以调用一百二十万次。这个速度是不经过连接而直接进行回调的速度的十分之一。请注意这里的十分之一速度比是调用速度的比较,而不是一个完整函数执行时间的比较。事实上一般情况下一个函数的总执行时间大部分是在执行部分,只有小部分是在调用部分,因些这个速度是可以接受的。这就象面向对象的编程和早些年的结构化编程相比一样:

程序的执行效率并没有提高,反而是有所下降的,但现在大家都在用面向对象的方法编写程序。用一部分执行效率换回开发效率与维护效率是值得的,况且现在已是P4为主流的时代。

我们先来看一个简单的样例:

class Demo : public QObject
{Q_OBJECTpublic:Demo();int value() const { return val; };public slots:void setValue( int );signals:void valueChanged( int );private:int val;
};/*由样例可看到,类的定义中有两个关键字slots和signals,还有一个宏Q_OBJECT。在Qt的程序中如果使
用了信号与反应槽就必须在类的定义中声明这个宏,不过如果你声明了该宏但在程序中并没有信号与反应槽,对
程序也不会有任何影响,所以建议大家在用Qt写程序时不妨都把这个宏加上。使用slots定义的就是信号的功能
实现,即反应槽,例如:*/void Demo::setValue( int v )
{if ( v != val ){val = v;emit valueChanged(v);}
}/*这段程序表明当setValue执行时它将释放出valueChanged这个信号。以下程序示范了不同对象间信号与反应槽的连接。*/Demo a, b;connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));b.setValue( 11 );a.setValue( 79 );b.value(); // b的值将是79而不是原先设的11

在以上程序中,一旦信号与反应槽连接,当执行a.setValue(79)时就会释放出一个valueChanged(int)的信号,对象b将会收到这个信号并触发setValue(int)这个函数。当b在执行setValue(int)这个函数时,它也将释放valueChanged(int)这个信号,当然b的信号无人接收,因此就什么也没干。请注意,在样例中我们仅当输入变量v不等于val时才释放信号,因此就算对a与b进行了交叉连接也不会导致死循环的发生。由于在样例中使用了Qt特有的关键字和宏,而Qt本身并不包括C++的编译器,因此如果用流行的编译程序(如Windows下的Visual C++或Linux下的gcc)是不能直接编译这段代码的,必须用Qt的中间编译工具moc.exe把该段代码转换为无专用关键字和宏的C++代码才能为这些编译程序所解析、编译与链接。

以上代码中信号与反应槽的定义是在类中实现的。那么,非类成员的函数,比如说一个全局函数可不可以也这样做呢?答案是不行,只有是自身定义了信号的类或其子类才可以发出该种信号。一个对象的不同信号可以连接至不同的对象。当一个信号被释放时,与之连接的反应槽将被立刻执行,就象是在程序中直接调用该函数一样。信号的释放过程是阻塞的,这意味着只有当反应槽执行完毕后该信号释放过程才返回。如果一个信号与多个反应槽连接,则这些反应槽将被顺序执行,排序过程则是任意的。因此如果程序中对这些反应槽的先后执行次序有严格要求的,应特别注意。使用信号时还应注意:信号的定义过程是在类的定义过程即头文件中实现的。为了中间编译工具moc的正常运行,不要在源文件(.cpp)中定义信号,同时信号本身不应返回任何数据类型,即是空值(void)。如果你要设计一个通用的类或控件,则在信号或反应槽的参数中应尽可能使用常规数据以增加通用性。如上例代码中valueChanged的参数为int型,如果它使用了特殊类型如QRangeControl::Range,那么这种信号只能与RangeControl中的反应槽连接。如前所述,反应槽也是常规函数,与未定义slots的用户函数在执行上没有任何区别。

但在程序中不可把信号与常规函数连接在一起,否则信号的释放不会引起对应函数的执行。要命的是中间编译程序moc并不会对此种情况报错,C++编译程序更不会报错。初学者比较容易忽略这一点,往往是程序编好了没有错误,逻辑上也正确,但运行时就是不按自己的意愿出现结果,这时候应检查一下是不是这方面的疏忽。

Qt的设计者之所以要这样做估计是为了信号与反应槽之间匹配的严格性。既然反应槽与常规函数在执行时没有什么区别,因此它也可以定义成公共反应槽(public slots)、保护反应槽(protected slots)和私有反应槽(private slots)。如果需要,我们也可以把反应槽定义成虚函数以便子类进行不同的实现,这一点是非常有用的。

QT 中 关键字讲解(emit,signal,slot)以及使用相关推荐

  1. qt中emit signal slot

    qt中emit signal slot qt中的类库有很多都是从QObject上继承下来的, 信号与反应槽(signals/slot)机制就是用来在QObject类或其子类之间通信的一种方法.作为一种 ...

  2. QT中简单的emit使用

    1.在这里需要感谢一下九月小姐姐的亲情帮助! 2.在这个一般使用emit的时候都是用户自定义的一个信号,废话少说上代码. 1.这里是两个不相关的类,在qt里可以是两个界面也可以是别的什么.这个一般都是 ...

  3. QT中出现 : No such signal QPushButton

    No such signal QPushButton :: clicked(const Qstring &) in connect(ui->LoginButton,SIGNAL(clic ...

  4. Qt signal slot 实现机制

    今天被问到一个问题,如下:Qt的signal slot的实现机制. 现在整理一下: 概述 信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解.信号和槽是一种高级接口,应用于对象之间的 ...

  5. Qt5 中的 signal/slot 新语法

    Qt 5 Alpha 已经发布.我们会在后面的文章中看到 Qt 5 的新变化.今天,我们先来看一下 Qt 5 带来的一个最主要的变化:signal/slot 机制的改变. Qt 5 之前的语法 在 Q ...

  6. QT中的Singal\slot机制

    QT中的Singal\slot机制 在QT工程项目中,会使用到多窗口或者二级窗口,而窗口之间做数据交流时,可以使用信号\槽机制,将两个不相关的对象相连,达到数据传输的效果. 语法 Connect函数 ...

  7. 【Qt】Qt中信号与槽

    00. 目录 文章目录 00. 目录 01. 信号与槽 02. 介绍 03. 信号与槽 04. 信号 05. 槽 06. 一个小例子 07. 一个真实的例子 08. 信号和槽使用默认参数 09. 信号 ...

  8. linux创建自定义组件qt,QT中的元对象系统:创建自定义的QT类型

    原创文章,转载请注明出处,谢谢! 作者:清林,博客名:飞空静渡 QVariant可以表示QT中的大部分类型,它和pascal中的variant类型或c中的void类型有点相似,不过它的使用和c中的un ...

  9. QT中如何实现Thread与GUI的主线程连通

    QT中如何实现Thread与GUI的主线程连通 本文介绍的是QT中实现Thread与GUI主线程通,目前只会一种,采用信号槽机制. 通常情况下,信号和槽机制可以同步操作,这就意味着在发射信号的时候,使 ...

最新文章

  1. Linux 系统调用(二)——使用内核模块添加系统调用(无需编译内核)
  2. 中兴服务器raid配置_-服务器Raid卡更换后如何恢复硬盘Raid组信息
  3. linux文件类型elf,[Linux]四种ELF对象文件类型
  4. Java中那些内存泄漏的场景!
  5. jquery Datatables 行数据删除、行上升、行下降功能演示
  6. BUPT复试专题—C翻转(2010)
  7. 用Keras搭建神经网络 简单模版(三)—— CNN 卷积神经网络(手写数字图片识别)...
  8. 【智能算法第一期】Elman神经网络基本原理
  9. struct termios 结构体详解
  10. 高等数学教材上册复习
  11. 2021-06-01winserver2008R2溢出提权(转)
  12. 使用 net C 发送邮件(带成功案例)
  13. 视频号账号定位怎么做?如何做微信视频号定位
  14. 阿里云服务器包年包月/按量计费/抢占式实例模式选择方法
  15. wince 读写 ini 文件 操作 MFC
  16. 移动物联网项目搭建(一)——起步
  17. Java基于JSP的论坛交流系统
  18. matlab画一个放大图中图
  19. .sh(shell)文件打印文件夹下所有文件的文件名
  20. 图示电路中的等效电阻rab_求图所示电路的等效电阻Rab

热门文章

  1. PostgreSQL在何处处理 sql查询之二十一
  2. javascript事件模型框架
  3. 给线程变量pthread_t *thread动态分配空间
  4. 初等数学O 集合论基础 第二节 映射与集合的势
  5. 脑与认知科学2 脑神经电生理学上
  6. 在8086模拟器中运行汇编求平均值程序
  7. SQL注入语法类型——报错注入
  8. seleniumIDE
  9. 基于R语言的时间序列分析预测
  10. 深入解读Python的unittest并拓展HTMLTestRunner