QT信号槽详解
1 QT信号槽详解
1.1 信号和槽的定义
信号是触发信号,例如按钮的点击触发一个clicked信号,槽是用来接收信号,并处理信号,相当于信号响应函数。一个信号可以关联多个槽函数,信号也可以连接信号。
要使用信号槽,类必须继承与QObject类或者其子类,否则无法识别槽函数错误。在类的定义开头需要添加宏定义Q_OBJECT。如下
class AlarmCenter : public QWidget
{
Q_OBJECT
//用关键字signals定义信号,关键字slots定义槽函数。如下所示:
public slots:
void SlotHideNoPlatPalyerTip(int tip);
signals:
void signalHideNoPlatPalyerTip (int tip);
}
信号和槽函数之间采用connect函数进行连接,采用disconnect函数取消连接。在需要触发信号的地方,采用关键字emit signalHideNoPlatPalyerTip (3);触发信号,调用槽函数,传入参数。
1.2 信号槽的连接方式
1.2.1 按照名称自动关联
自动关联需要响应函数的名称按照格式 on_按钮的名称_信号名称()来书写,并将该函数声明为槽slots。点击按钮的时候就会自动关联该信号到该响应函数。
头文件中:
public slots:
void on_BtnStart_clicked();
源文件中:
void AlarmCenter::on_BtnStart_clicked()
{
int i = 0;
}
1.2.2 Connect连接信号与槽函数
(1)无参数信号槽函数连接
&获取指针需要指定类名称,用宏定义SIGNAL和SLOT可以直接指定函数名称。
QObject::connect(ui.fliterBtn, &QToolButton::clicked, this, &AlarmCenter::DisplayFliterWidget);
connect(ui.fliterBtn, SIGNAL(clicked()), this, SLOT(DisplayFliterWidget ()));
(2)有参数信号槽函数连接
signals:
void valueChanged(int value);
slots:
void AlarmCenter::AlarmListVScrool(int position);
&方式无需添加参数,SIGNAL和SLOT方式则要添加参数,注意使用&方式时,如果槽函数是重载函数,则编译出错,因为没有参数,无法判断是连接哪个槽函数,所以建议采用,SIGNAL和SLOT方式带上参数。多个参数用逗号隔开,只添加形参类型,不加形参实体。
QObject::connect(ui.verticalScrollBarAlarm, &QScrollBar::valueChanged, this, &AlarmCenter::AlarmListVScrool);
QObject::connect(ui.verticalScrollBarAlarm, SIGNAL(valueChanged(int)), this, SLOT(AlarmListVScrool(int)));
对于有重载函数的槽函数,需要用到有参数的连接方式,否则无法判断是哪个槽函数。
(3)自定义结构体参数的信号槽连接
对于自定义的结构体参数,信号槽无法识别参数,导致信号槽连接不起作用。所以需要注册结构体参数。在结构体中声明结束的地方加上结构体注册。
struct DealDetailInfo
{
};
Q_DECLARE_METATYPE(DealDetailInfo);
信号定义
signals:
void signalOnePointUpdateData(QVariant VarDetailInfo);
槽函数定义
void SlotOnePointUpdateData(QVariant VarDealInfo);
信号槽连接
QObject::connect(&m_DealDetail, SIGNAL(signalOnePointUpdateData(QVariant)), this, SLOT(SlotOnePointUpdateData(QVariant)), Qt::QueuedConnection);
发送信号的地方用变量QVariant包装结构体参数
QVariant DataVar;
DataVar.setValue(DetailInfo);
emit signalOnePointUpdateData(DataVar);
接收信号的地方从包装中取出结构体参数
DealDetailInfo DealInfo;
DealInfo= VarDealInfo.value<DealDetailInfo>();
1.2.3 信号与信号连接
当存在复杂的包含关系时,A是B的成员对象,B是C的成员对象。在A中触发的信号需要C中的槽函数响应,则需要连接A中的信号触发B中的信号,B中的信号触发C中的槽函数。例子如下:
Class A
{
signals:
signalChangeColor(int i);
}
Class B
{
signals:
signalChangeColor(int i);
privite:
A a;
}
QObject::connect(&a,SIGNAL(signalChangeColor(int)), this, SIGNAL(signalChangeColor(int)));
Class C
{
public lots:
SlotChangeColor(int i)
privite:
B b;
}
QObject::connect(&b,SIGNAL(signalChangeColor(int)),this, SLOT(SlotChangeColor(int i)));
1.2.4 信号和lambda表达式连接
当槽函数比较简单,没有必要创建一个槽函数去连接,可以直接用一段简短的代码作为信号接收处理。日下所示。
QObject::connect(ui.closeDisPlayImageWndBtn, &QToolButton::clicked, this, [=]()
{
m_imageWidth = 0;
m_imageHeight = 0;
m_iPercent = 100;
m_izoomLevel = 0;
close();
});
或者控件是new出来的,需要关联控件信号到函数
QCheckBox *CheckBox = new QCheckBox(ui.tableWidget);
QSize size(39, 35);
CheckBox->setFixedSize(size);
CheckBox->setCheckState(Qt::Unchecked);
QObject::connect(CheckBox, &QCheckBox::clicked,this, [=]()
{
AlarmTableItemChoosed(step, 0);//成员函数
});
1.2.5 QT Designer界面上连接信号槽
进入QT Designer 界面,点击信号槽编辑按钮,进入信号槽编辑界面,拖动按钮,对按钮的信号槽进行编辑,可以选用已有的槽,或者点击编辑按钮,新增自定义槽。关联之后,在ui_*.h(*表示对话框类名)中会自动添加一行,QObject::connect(BtnStart, SIGNAL(clicked()), AlarmCenterClass, SLOT(sbclslot()));然后在dialog类的文件中实现该槽。

1.3 信号槽的连接响应类型
连接信号与槽的connect()函数原型如下:
bool QObject::connect ( const QObject * sender, const QMetaMethod & signal, const QObject * receiver, const QMetaMethod & method, Qt::ConnectionType type = Qt::AutoConnection );
最后一个参数Qt::ConnectionType是连接类型,不同的连接类型,槽函数的响应策略如下:
|
Constant |
Value |
Description |
|
Qt::AutoConnection |
0 |
自动识别。当信号发送者和接收者处于同一线程内时,这个类型等同于DirectConnection,反之等同于QueuedConnection,这个类型也是connect函数的默认连接类型 |
|
Qt::DirectConnection |
1 |
同步执行。信号一旦发射,与之关联的槽函数立即执行,执行返回后才能执行emit之后的代码,相当于函数调用。 |
|
Qt::QueuedConnection |
2 |
异步执行。当信号产生,信号会暂时被缓冲到一个消息队列中,不用等待槽函数返回,就会执行后面的代码。等待接收者的事件循环处理去队列中获取消息,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作 |
|
Qt::BlockingQueuedConnection |
3 |
阻塞执行。这种类型类似于QueuedConnection,但是它只能应用于跨线程操作即发送者和接收者处于不同的线程中的情况,并且信号发送者线程会阻塞等待接收者的槽函数执行结束。如果是同一个线程调用,会造成死锁现象。 |
|
Qt:: Unique Connection |
0x80 |
作用相当于Qt::AutoConnection。只是防止重复连接。如果当前信号和槽已经连接过了,就不再连接了。 |
1.4 一个信号多个槽函数的调用顺序
存在一个信号连接多个槽函数的情况,槽函数的调用顺序与连接的先后一致,但这只适用于同步调用,异步调用是加入到信号队列中,无法判断调用先后顺序。
1.5 带返回值的信号
大都说Qt信号槽不能使用返回值。Qt5中,信号槽是有返回值的。只是Qt的一个信号可以连接多个槽,还有同步调用和异步调用的问题,没发支持的很好,所以,返回值虽有,但只是鸡肋。同步调用才有返回值,异步调用的返回值永远为返回值类型默认构造函数出来的。连接的多个槽都返回值,那么结果是最后调用(连接)的那个。也就是说对于QueuedConnection连接的信号槽,永远只是返回返回类型的默认构造函数的。对于AutoConnection连接的,如果发出信号的线程和槽函数线程不同亦然。所以只有同步调用或者阻塞调用,才会成功返回值。
bool bReturn;
QMetaObject::invokeMethod(&object, "signalname", Qt::DirectConnection/* Qt::BlockingQueuedConnection */, Q_RETURN_ARG(bool, bReturn), Q_ARG(int, i));
QT信号槽详解的更多相关文章
- QT源码之Qt信号槽机制与事件机制的联系
QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...
- Qt信号槽的一些事(第一次知道信号还有返回值,以及Qt::UniqueConnection)
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...
- QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类
一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如: QObject::connect: Can ...
- Qt信号槽的一些事 Qt::带返回值的信号发射方式
一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值.那么如果我们发出这个信号想获取一个返回值怎么办呢? 两个办法:1.通过出参形式返回,引用或者指 ...
- Qt信号槽的一些事
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...
- Qt信号槽-原理分析
目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...
- Qt信号槽源码剖析(一)
大家好,我是IT文艺男,来自一线大厂的一线程序员 大家在使用Qt开发程序时,都知道怎么使用Qt的信号槽,但是Qt信号槽是怎么工作的? 大部分人仍然不知道:也就是说大家只知道怎么使用,却不知道基于什么原 ...
- Qt信号槽源码剖析(二)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的基本概念.元对象编译器.示例代码以及Qt宏:今天接着深入分析,进入Qt信号槽源码剖析系列的第二节视频. Qt信号槽的宏 ...
- (文字版)Qt信号槽源码剖析(三)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的Qt宏展开推导:今天接着深入分析,进入Qt信号槽源码剖析系列的第三节视频. Qt信号槽宏推导归纳 #define si ...
随机推荐
- Docker学习笔记之通过 Dockerfile 创建镜像
0x00 概述 由于 Docker 镜像的结构优势,使它的占用空间远小于普通的虚拟机镜像,而这就大幅减少了 Docker 镜像在网络或者其他介质中转移所花费的时间,进而提高了我们进行迁移部署的效率.不 ...
- Systen,IO
private void CreateHtml(string sPath, string txt) { string currPath = @"C:\MyCodeHelper" + ...
- 百度uid-generator源码
https://github.com/baidu/uid-generator snowflake算法 uid-generator是基于Twitter开源的snowflake算法实现的. snowfla ...
- mint-ui之datetime-picker使用
一基本使用<template> <mt-datetime-picker ref="picker" type="time" v-model=&q ...
- 一、数据库表中字段的增删改查,二、路由基础.三、有名无名分组.四、多app共存的路由分配.五、多app共存时模板冲突问题.六、创建app流程.七、路由分发.八、路由别名,九、名称空间.十、反向解析.十一、2.x新特性.十二、自定义转换器
一.数据库表中字段的增删改查 ''' 直接在modules中对字段进行增删改查 然后在tools下点击Run manage.py Task执行makemigrations和migrate 注意在执行字 ...
- 理解Linux文件系统之 inode
一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统读取硬盘的时候,不会 ...
- 【Python48--魔法方法:迭代器&生成器】
一.迭代器 1.iter() __iter__() 2.next() __next__() 二.用while语句实现for语句相同的功能 for each in range(5): print(eac ...
- linux基础之程序包管理(rpm,yum)
一.rpm 安装:rpm { -i | --install } [ install-options ] PACKAGE_FILE... -v: 显示安装时的详细信息 -vv: 显示许多难以阅读的调试信 ...
- .NET Standard vs. .NET Core
What is the difference between .NET Core and .NET Standard Class Library project types? Answer1 When ...
- .Net Core之Swagger
1.项目生成xml 2.添加链接文件,并将属性设值为始终复制 3.添加swagger引用:Swashbuckle.AspNetCore 4.startup.cs配置swargger的xml来源: Co ...