信号槽是Qt中最重要的机制,现将信号槽的基本用法总结如下。

1、定义

信号槽类似于软件设计模式中的观察者模式,(观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。)被观察者发出的信号(signal),观察者收到自己注册监听signal,就通过槽(slot)关联的槽函数function实现动作操作。

信号槽优点:

(1)类型安全

信号的参数类型、参数个数需要和槽函数的参数类型和参数个数一致。槽函数的个数可以少于信号的参数个数,但缺少的参数必须是信号参数的最后一个或最后几个。

(2)松散耦合

信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt的信号槽机制保证了信号与槽函数的调用。支持信号槽机制的类或者父类必须继承于QObject。

(3)效率

信号槽增强了对象间通信的灵活性,同时损失了一些性能,通过信号调用的槽函数比直接调用速度慢约10倍(因为需要定位信号接收者;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调用速度对性能要求不是非常高的场景是可以忽略的,是满足绝大部分场景。

注:

信号:没有访问权限修饰符,是公有的,没有函数体定义返回类型是 void,信号在 moc 自动产生。

槽函数:需要有访问权限修饰:public,private,protected。

2、关联信号槽的方法

通过connect关联信号和槽函数

(1)Qt5以前的connect有以下几种:

bool connect(const QObject *, const char *,const QObject *, const char *,Qt::ConnectionType);bool connect(const QObject *, const QMetaMethod &,const QObject *, const QMetaMethod &,Qt::ConnectionType);bool connect(const QObject *, const char *,const char *,Qt::ConnectionType) const

Qt4使用了SIGNAL和SLOT这两个宏,将信号和槽的函数名转换成了字符串。注意,不能将全局函数或者 Lambda 表达式传入connect()。使用字符串导致了Qt4有以下缺点:一旦出现连接不成功的情况,Qt 4 是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。

第一种是比较常用的,可简单描述如下:

connect(obj1, SIGNAL(fun1(param1, param2,...)), obj2, SLOT(fun2(param1,...)));

优点:对所有控件都适用。

缺点:书写繁琐,槽函数必须在slot标签下。在程序编译阶段,程序会将函数以字符串的形式进行链接,程序不会检查信号/槽函数是否存在,只有在运行期间才会验证是否正确

(2)Qt5写法有以下几种


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);

相对Qt5以前,第四种和第五种是新增的。

第四种比较常用,可简单描述如下:

connect(obj1, &ClassA::fun1, obj2, &ClassB::fun2);

优点:书写简便,编译期间就会检查信号与槽是否存在,参数类型检查,Q_OBJECT是否存在,槽函数不在限定必须是slot,可以是普通的函数、类的普通成员函数、lambda函数。

缺点:函数重载,有可能会造成程序的困扰,不知道该具体链接哪个

解决:a)可以使用Qt5以前的写法。

          b)或者使用函数指针,eg:

 connect(comboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),[=](int index){ /* ... */ });

关于connect几种函数的详细介绍可参考Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)_花园王国---Garden kingdom-CSDN博客

3、信号槽的性质

(1)一个信号可以关联多个槽函数。

connect(obj1,SIGNAL(signal1),obj1,SLOT(fun1()));
connect(obj1,SIGNAL(signal1),obj1,SIGNAL(fun2()));
connect(obj1,SIGNAL(signal1),obj1,SIGNAL(fun3()));

注:Qt5以后,支持按照建立连接的顺序触发槽函数。即如果一个信号连接到多个槽,则在发出信号时,这些槽的激活顺序与建立连接的顺序相同。If a signal is connected to several slots, the slots are activated in the same order in which the connections were made, when the signal is emitted.

Qt5以前:信号发射时,与之相关联的槽的执行顺序将是随机的,且顺序不能指定。执行结果:

(2)多个信号可以关联一个槽函数。

connect(obj1,SIGNAL(signal1),obj1,SLOT(fun1()));
connect(obj2,SIGNAL(signal2),obj1,SIGNAL(fun1()));
connect(obj3,SIGNAL(signal3),obj1,SIGNAL(fun1()));
//槽函数可以根据sender()->objectName()来判断是哪个信号触发的槽函数

(3)一个信号可以关联另一个信号。

connect(obj1,SIGNAL(signal1),obj2,SIGNAL(signal2));

(4)一个信号关联多个信号

connect(obj1,SIGNAL(signal1),obj2,SIGNAL(signal21));
connect(obj1,SIGNAL(signal1),obj2,SIGNAL(signal22));
connect(obj1,SIGNAL(signal1),obj2,SIGNAL(signal23));

demo如下:

///.h///
#pragma once#include <QtWidgets/QWidget>
#include "ui_SignalSlot.h"
#include <QTimer>
class SignalSlot : public QWidget
{Q_OBJECTpublic:SignalSlot(QWidget *parent = Q_NULLPTR);public slots://响应btn1void  OnBtn1();void   OnSetTextStyle();void   OnSetWindowTitile();//响应自定义信号void   OnSignalMsg();//响应btn2 clickedvoid  OnBtn2Signal();//响应自定义信号void    OnCustomSignal(int x,int y);//自定义信号
signals:void signalMsg1();void  signalMsg2();void  signalMsg3();void  signalMsg(int x,int y);
private:Ui::SignalSlotClass ui;QTimer *m_pTimer;
};.cpp
#include "SignalSlot.h"
#include <qDebug>
#include <qevent.h>
SignalSlot::SignalSlot(QWidget *parent): QWidget(parent)
{ui.setupUi(this);///一个信号关联多个槽函数 start//connect(ui.pbtn1,SIGNAL(clicked()),this,SLOT(OnBtn1()));connect(ui.pbtn1, SIGNAL(clicked()), this, SLOT(OnSetTextStyle()));connect(ui.pbtn1, SIGNAL(clicked()), this, SLOT(OnSetWindowTitile()));/一个信号关联多个槽函数 end///多个信号关联一个槽函数 start//connect(this, SIGNAL(signalMsg1()), this, SLOT(OnSignalMsg()()));connect(this, SIGNAL(signalMsg2()), this, SLOT(OnSignalMsg()()));connect(this, SIGNAL(signalMsg3()), this, SLOT(OnSignalMsg()()));///多个信号关联一个槽函数 end/////一个信号关联多个信号 start/////一个信号关联一个信号 start//connect(this, SIGNAL(signalMsg3()), ui.pbtn2, SIGNAL(clicked()));connect(ui.pbtn2, SIGNAL(clicked()), this, SLOT(OnBtn2Signal()));///一个信号关联一个信号 end//connect(this, SIGNAL(signalMsg3()), ui.pbtn2, SIGNAL(pressed()));connect(ui.pbtn2, &QPushButton::clicked, this,&SignalSlot::OnBtn2Signal);///一个信号关联多个信号 end/////带参信号槽/
connect(this, SIGNAL(signalMsg(int,int)), this, SLOT(OnCustomSignal(int,int)));///信号槽lambda写法/m_pTimer = new QTimer(this);connect(m_pTimer, &QTimer::timeout, [=]() {ui.lineEdit3->setText(QString::fromLocal8Bit("你好,中国"));ui.lineEdit4->setText(QString::fromLocal8Bit("你好,中国"));qDebug() << "11111" << endl;m_pTimer->stop();});m_pTimer->start(1000*10);//启动定时器
}void SignalSlot::OnBtn1()
{ui.lineEdit1->setText(QString::fromLocal8Bit("你好,世界!"));qDebug() << "OnBtn1" <<endl;emit signalMsg(2,3);
}void SignalSlot::OnSetTextStyle()
{ui.lineEdit1->setStyleSheet(" QLineEdit{ background: yellow }");qDebug() << "OnSetTextStyle" << endl;
}void SignalSlot::OnSetWindowTitile()
{this->setWindowTitle(QString::fromLocal8Bit("测试窗口"));qDebug() << "OnSetWindowTitile" << endl;emit signalMsg1();emit signalMsg2();emit signalMsg3();
}void SignalSlot::OnSignalMsg()
{qDebug() << sender()->objectName() << endl;
}void SignalSlot::OnBtn2Signal()
{ui.lineEdit2->setText(QString::fromLocal8Bit("你好,中国"));qDebug() << "OnBtn2Signal"<< endl;
}void SignalSlot::OnCustomSignal(int x, int y)
{qDebug() << "x" << x << ",y" << y << endl;
}

执行结果

备注:

lambda用法可参考:C++中的Lambda表达式详解_NickWei的博客-CSDN博客_lambda表达式c++

lambda函数定义如下:

[capture](parameters) mutable ->return-type{statement}

(1)[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;

(2)(parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;

(3)mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);

(4)->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;

(5){statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。

与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:

(1)[var]表示值传递方式捕捉变量var;

(2)[=]表示值传递方式捕捉所有父作用域的变量(包括this);
(3)[&var]表示引用传递捕捉变量var;
(4)[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
(5)[this]表示值传递方式捕捉当前的this指针。

Qt的信号槽基本用法总结相关推荐

  1. qt 关闭窗口的槽函数_勇哥的VC++应用框架学习之QT(1) 信号槽、按钮控件、opencv读取显示图片...

    前言勇哥对于C语言,C++早些年有一些接触,这个系列贴子就记载一下C++应用框架的学习经验. 在写程序时,UI.基础类库.应用程序框架对于vc来讲,只能依靠MFC和QT了. 勇哥对MFC有很强的抵触, ...

  2. 学习QT之信号槽机制详解

    学习QT之信号槽机制详解 一.Qt信号槽机制 概念:信号槽是Qt框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如:按钮检测到自己被点击了一下,它就会发出一个信号(sig ...

  3. Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)

    转载地址: https://blog.csdn.net/nicai888/article/details/51169520 一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说: ...

  4. python简单消息总线实现,类似于C++ Qt的信号槽

    一. 概述 为了模块间解耦,消息总线是常用的方式. 在其它文章中分别提到了lua和C++语言的消息总线的实现 lua语言的消息总线的实现:lua简单消息总线实现,类似于C++ Qt的信号槽 cpp语言 ...

  5. QT Core | 信号槽01 - GUI上按钮触发应用程序里某个类的函数

    文章目录 一.前言 二.新建一个QT项目 2.1.New File or Project 2.2.Location 2.3.Kits 2.4.Details 2.5.汇总 2.6.项目文件 2.7.p ...

  6. Qt的信号槽机制介绍

    Qt 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 Qt ...

  7. Boost::signals2 类QT的信号槽实现机制

    signals2 基于Boost里的另一个库signals,实现了线程安全的观察者模式.它是一种函数回调机制,当一个信号关联了多个槽时,信号发出,这些槽将会被调用.google的base库里用的多的模 ...

  8. QT Core | 信号槽03 - 自定义信号与槽

    文章目录 一.前言 二.新建一个QT控制台项目 2.1.New File or Project 2.2.Project Location 2.3.Define Build System 2.4.Kit ...

  9. QT中信号槽的概念及使用

    文章目录 信号槽的概念 函数原型 信号槽连接的三种方式 方式一 方式二 方式三 参数传递 全局参数 信号槽传参 信号槽的对应关系 总结 信号槽的概念 信号函数与槽函数是 Qt 在 C++ 的基础上新增 ...

  10. qt connect函数_小白学QT 使用VS 给 qt 添加信号槽

    VS中的QT设计器 1 自定义槽函数 右键没有转到槽 自动添加槽的功能,需要手动添加下 比如: private slots: void Btn_OpenClick(); #include #inclu ...

最新文章

  1. 维护一套同时兼容 iOS 6 和 iOS 7,并且能够自动适应两个系统的 UI 风格的代码...
  2. mysql性能分析工具profiling_Mysql系列(十)—— 性能分析工具profiling
  3. redis源码分析 ppt_Redis源码分析之客户端+数据库
  4. php小白书,php小白的自学第一天
  5. JavaScript中一个对象如何继承另外一个对象
  6. python行与缩进_Python行结构与缩进的简单介绍
  7. Python中变量的本质探索
  8. 查询本地内存的栈大小_Js的内存问题
  9. python numpy数组动态写入csv文件_python - 将NumPy数组转储到csv fi中
  10. SAP系统登录以及注册开发人员
  11. android免root hook框架legend
  12. 语音信号处理-概念(三):FBank特征、MFCC特征(梅尔频率倒谱系数)【由于二者蕴含信息较少,已不适合这个大数据时代。但有些任务由于其本身的特殊性质,还是会使用到MFCC谱。如情感语音转换任务】
  13. Excel 2007 设置每页打印标题
  14. vue3状态管理pinia、 路由useRouter
  15. C语言关于qsort函数的用法详细说明
  16. 扇形图形用html,css如何画扇形?
  17. 003 免格式化U盘部署PE(UEFI)
  18. centso7.2上mysql安装
  19. NC65【新】功能快速开发详细教程(yyds神)
  20. 数据类型(一)基本的数据类型

热门文章

  1. 对 数组[i].index=i的理解
  2. html代码表白_作为一个程序员,表白都要玩出花样
  3. 网页隐藏index.php,如何隐藏url中的index.php
  4. python遍历目录压缩文件夹_zip包含一个档案文件夹,如何使用Python获取存档中每个zip的注释?...
  5. python类属性定义_Python中类的定义与使用
  6. fullcalendar 只保留周_用枝条扦插橡皮树太浪费,只需一个“叶片”,就能变成一棵橡皮树...
  7. LeetCode 74.搜索二维矩阵
  8. php php-fpm安装 nginx配置php
  9. 图文详细解说DevExpress 2015新版亮点【附文档下载】
  10. centos 6.5 安装qt5.2