Qt的信号槽基本用法总结
信号槽是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的信号槽基本用法总结相关推荐
- qt 关闭窗口的槽函数_勇哥的VC++应用框架学习之QT(1) 信号槽、按钮控件、opencv读取显示图片...
前言勇哥对于C语言,C++早些年有一些接触,这个系列贴子就记载一下C++应用框架的学习经验. 在写程序时,UI.基础类库.应用程序框架对于vc来讲,只能依靠MFC和QT了. 勇哥对MFC有很强的抵触, ...
- 学习QT之信号槽机制详解
学习QT之信号槽机制详解 一.Qt信号槽机制 概念:信号槽是Qt框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如:按钮检测到自己被点击了一下,它就会发出一个信号(sig ...
- Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)
转载地址: https://blog.csdn.net/nicai888/article/details/51169520 一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说: ...
- python简单消息总线实现,类似于C++ Qt的信号槽
一. 概述 为了模块间解耦,消息总线是常用的方式. 在其它文章中分别提到了lua和C++语言的消息总线的实现 lua语言的消息总线的实现:lua简单消息总线实现,类似于C++ Qt的信号槽 cpp语言 ...
- 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 ...
- Qt的信号槽机制介绍
Qt 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 Qt ...
- Boost::signals2 类QT的信号槽实现机制
signals2 基于Boost里的另一个库signals,实现了线程安全的观察者模式.它是一种函数回调机制,当一个信号关联了多个槽时,信号发出,这些槽将会被调用.google的base库里用的多的模 ...
- QT Core | 信号槽03 - 自定义信号与槽
文章目录 一.前言 二.新建一个QT控制台项目 2.1.New File or Project 2.2.Project Location 2.3.Define Build System 2.4.Kit ...
- QT中信号槽的概念及使用
文章目录 信号槽的概念 函数原型 信号槽连接的三种方式 方式一 方式二 方式三 参数传递 全局参数 信号槽传参 信号槽的对应关系 总结 信号槽的概念 信号函数与槽函数是 Qt 在 C++ 的基础上新增 ...
- qt connect函数_小白学QT 使用VS 给 qt 添加信号槽
VS中的QT设计器 1 自定义槽函数 右键没有转到槽 自动添加槽的功能,需要手动添加下 比如: private slots: void Btn_OpenClick(); #include #inclu ...
最新文章
- 维护一套同时兼容 iOS 6 和 iOS 7,并且能够自动适应两个系统的 UI 风格的代码...
- mysql性能分析工具profiling_Mysql系列(十)—— 性能分析工具profiling
- redis源码分析 ppt_Redis源码分析之客户端+数据库
- php小白书,php小白的自学第一天
- JavaScript中一个对象如何继承另外一个对象
- python行与缩进_Python行结构与缩进的简单介绍
- Python中变量的本质探索
- 查询本地内存的栈大小_Js的内存问题
- python numpy数组动态写入csv文件_python - 将NumPy数组转储到csv fi中
- SAP系统登录以及注册开发人员
- android免root hook框架legend
- 语音信号处理-概念(三):FBank特征、MFCC特征(梅尔频率倒谱系数)【由于二者蕴含信息较少,已不适合这个大数据时代。但有些任务由于其本身的特殊性质,还是会使用到MFCC谱。如情感语音转换任务】
- Excel 2007 设置每页打印标题
- vue3状态管理pinia、 路由useRouter
- C语言关于qsort函数的用法详细说明
- 扇形图形用html,css如何画扇形?
- 003 免格式化U盘部署PE(UEFI)
- centso7.2上mysql安装
- NC65【新】功能快速开发详细教程(yyds神)
- 数据类型(一)基本的数据类型
热门文章
- 对 数组[i].index=i的理解
- html代码表白_作为一个程序员,表白都要玩出花样
- 网页隐藏index.php,如何隐藏url中的index.php
- python遍历目录压缩文件夹_zip包含一个档案文件夹,如何使用Python获取存档中每个zip的注释?...
- python类属性定义_Python中类的定义与使用
- fullcalendar 只保留周_用枝条扦插橡皮树太浪费,只需一个“叶片”,就能变成一棵橡皮树...
- LeetCode 74.搜索二维矩阵
- php php-fpm安装 nginx配置php
- 图文详细解说DevExpress 2015新版亮点【附文档下载】
- centos 6.5 安装qt5.2