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 ...
随机推荐
- python的paramiko模块-远程登录linux主机并操作
paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作. 如果python服务器对被远程控制机器开启了免密验证,即在python服务器上可通过ssh 用户名@被控制机 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- Spring Boot 2 (七):Spring Boot 如何解决项目启动时初始化资源
Spring Boot 2 (七):Spring Boot 如何解决项目启动时初始化资源 在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等.今天就给大家介绍一个 Spri ...
- Iterator和Iterable的区别以及使用
Iterator和Iterable的区别以及使用 1.什么是迭代器 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.迭代 ...
- SPOJ Meteors - 可持久化线段树 - 二分法
Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby galaxy. The plan ...
- XcodeProj,使用Ruby更改工程文件
利用xcodeproj修改xcode工程文件 一,Ruby基础 Ruby迭代器each.map.collect.inject each——连续访问集合的所有元素collect—-从集合中获得各个元素传 ...
- 【做题】CF119D. String Transformation——KMP
题意:有两个字符串\(a,b\),下标从\(0\)开始.求数对\((i,j)\)满足\(a[i+1:j] + r(a[j:n]) + r(a[0:i+1]) = b\),其中\(r(s)\)表示字符串 ...
- Shiro源码分析
1.入口类:AbstractAuthenticator 用户输入的登录信息经过其authenticate方法: public final AuthenticationInfo authenticate ...
- 一个涉及到浮点寄存器的CM
这次找小伙伴要了他的一个CM,怎么说呢,这CM让我学到了不少,其实搞出来后感觉不难,就是有不少FPU浮点相关的指令和FPU寄存器完全没学过,查了不少资料,学到了很多 打开是这样 无壳程序,我们直接od ...
- SSM项目问题中遇到 ArrayList添加元素的问题
记录项目开发中 一次有趣的debug经历 本来是在做单元测试的,但是发现如下代码 有问题.. ProductCategory p = new ProductCategory(); for (int i ...