Qt-信号和槽

2023-11-19

一、Qt信号和槽机制&emit的使用

(一)相关概念

1.信号(Signal)就是在特定情况下被发射的事件

例如PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的 CurrentIndexChanged() 信号。GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。

2.槽(Slot)就是对信号响应的函数。槽就是一个函数

与一般的C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

3.信号与槽之间的关联:是用 QObject::connect() 函数实现的,其基本格式是:

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

//信号发出者,处理的信号, 信号接收者,处理动作方法(槽函数)。

注解:

  1. sender 是发射信号的对象的名称
  2. signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
  3. receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
  4. SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。

本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓ 

(二)注意点

1.一个信号可以连接多个槽, 当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行,例如:

  • connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
  • connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));

2.多个信号可以连接同一个槽

  • connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
  • connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
  • connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()))

3. 一个信号可以连接另外一个信号

4.严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。

5.使用signals/slots必须要加入宏Q_OBJECT

6. 当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。

7.一定要有signals关键字,定义信号时这个关键字不可或缺,比如我们定义一个信号void signal(),一定要在前面加上关键字“signals:”,

  • signals:
  • void signal();
  • 就像类中的public、protected、pravate一样,但是一定不能在signals前面加上public、protected、private,publi signals:这样写是错误的

8.slots可以写可以不写,一般的函数也可以与signals下的信号关联,我们定义槽函数时可以像signals那样加上slots关键字,也可以不加,但是需要注意的是,如果加上了,那就必须加上public、protected、paivate

  • public slots:
  • void func();这样写slots:void func();这样写就是错的
  • 当然不加上slots的一般函数也可以与信号关联

9.signals下的函数必须是void类型,而且只需要给出声明即可,具体实现QT内部自己处理,但是槽函数一定要实现,从我们角度思考是这种信号处理是一致的,但是槽函数的功能确实根据我们需要自己设计,所以有了这种差异。

10.信号与槽的参数不能是宏和函数指针

11.信号一般与emit配合使用,使用emit发射信号给关联的槽

12.connect若触发,它后面的不会再运行

(三)自定义槽

可当作槽函数的:任意的成员函数,普通全局函数,静态函数。

槽函数需要和信号一致(参数列表,返回值)如果信号没有返回值,槽函数一定没有返回值。

【举例】:让按钮2点击一下,就能改变按钮上的文本。

1.首先,在.h文件中声明:

 

2.在.cpp文件对该函数进行定义:

 

3.给按钮联结自定义的槽函数 mySlot:

connect(b2, &QPushButton::released, this, &MainWidget::mySlot);

4.运行

 

(四)自定义信号

1.信号必须有signals关键字来声明

2.信号没有返回值,但可以有参数。

3.信号就是函数的声明,只需声明,无需定义。

(五)emit发射信号

emit是Qt关键字,像其他关Qt扩展一样,它也会被C++预处理器转换成标准的C++代码。

使用:在A中对B使用信号

主要步骤:信号的创建,槽函数的创建,A类信号和B类槽函数的联接和使用

二、Connect几种方式

(一)说明

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

//信号发出者,处理的信号, 信号接收者,处理动作方法(槽函数)。
  1. sender 是发射信号的对象的名称
  2. signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
  3. receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
  4. SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。

1.

这应该是QT4.0最为传统的方法

 connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(pushButon1_clicked()));

2.

这应该是QT5.0之后退出来的绑定方法,去掉了之前的宏

 connect(ui->pushButton_2,&QPushButton::clicked,this,&::MainWindow::pushButon2_clicked);

3.

C++11出来之后,新的特性就出来,static_cast 用法

connect(ui->pushButton_3, QOverload<bool>::of(&QPushButton::clicked),this,&::MainWindow::pushButon3_clicked);

4.

lamda表达式

connect(ui->pushButton_4, QOverload<bool>::of(&QPushButton::clicked),[=](bool check){
                   ui->textBrowser->setText("按钮4信号绑定成功");
           });

如果槽函数很简单,可以直接利用 lambda表达式进行连接,以减少代码量

这里需要注意 Lambda表达式是C++ 11 的内容,所以,需要再Pro项目文件中加入 CONFIG += C++ 11

(二)例子

1.彻底退出

connect(quitAction,&QAction::triggered,[=](){this->close(); });

2.跳转其他页面

connect(m_button[0], &ClickLabel::clicked, this, [=]() {
        zoom(m_button[0]);
        m_guideScene->show();
        this->hide();
        });

3.connect嵌套

        //监听每个按钮的点击事件
        connect(menuBtn,&MyPushButton::clicked,[=](){
            ...
            //进入到游戏场景
            this->hide(); //将选关场景隐藏掉
            play = new PlayScene(i+1); //创建游戏场景
            //这里注意,每次点击按钮都会新建一个游戏场景对象指针,因此返回时应当删除
            ...
            play->show(); //显示游戏场景
            connect(play,&PlayScene::chooseSceneBack,[=](){
                this->setGeometry(play->geometry());//设定新窗口的坐标在屏幕上与原先窗口坐标相同
                this->show();
                delete play;
                play = NULL;
            });

        });
//点击返回//从子页面返回
connect(backBtn,&MyPushButton::clicked,[=](){
        QTimer::singleShot(500,[=](){
            emit this->chooseSceneBack();
        });
});

三、connect 第五个参数

(一)函数原型

connect 函数原型如下,第五个(5种)参数根据接收者和发送者是否在同一个线程不同

connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
        const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
        Qt::ConnectionType type = Qt::AutoConnection)

(二)Qt::ConnectionType 详解

1.Qt::AutoConnection

自动。一般不写就默认是这个,使用这个值会根据实际情况去判断,如果sender和receiver在同一个线程,则自动使用Qt::DirectConnection,如果不在一个线程,则自动使用Qt::QueuedConnection。

2.Qt::DirectConnection

直连。槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。

3.Qt::QueuedConnection

队列连接。槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

4.Qt::BlockingQueuedConnection

阻塞队列连接。槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

5.Qt::UniqueConnection

唯一连接。这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。

四、disconnect函数

disconect函数的原型如下:

bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)

(一)使用方法

一般有四种用法:

1.解除myObject对象的所有信号连接,调用后myObject对象发出的所有信号都得不到响应。

disconnect(myObject, 0, 0, 0);
//等同于
myObject->disconnect();

2.解除myObject对象的mySignal信号的所有连接,调用后myObject对象发出的mySignal信号得不到响应。

disconnect(myObject, SIGNAL(mySignal()), 0, 0);
//等同于
myObject->disconnect(SIGNAL(mySignal()));

3.解除myObject对象与myReceiver对象的信号连接,调用后myObject对象发出的所有信号得不到myReceiver对象的响应。

disconnect(myObject, 0, myReceiver, 0);
//等同于
myObject->disconnect(myReceiver);

4.解除myObject对象的mySignal信号与myReceiver对象的mySlot槽的连接,调用后myObject对象发出的mySignal信号得不到myReceiver对象的mySlot槽的响应。

disconnect(myObject, SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));
//等同于
myObject->disconnect(SIGNAL(mySignal(), myReceiver, SLOT(mySlot())));

上述4种用法中,0是通配符,它表示任一信号、任一接收对象、任一槽

五、blockSignals

blockSignals的函数原型如下:

bool QObject::blockSignals(bool block)

(一)用法

//object发出的信号被阻塞,系统不会调用任何连接到object的处理。
object->blockSignals(true);
 
//解除信号阻塞
object->blockSignals(false);

六、案例

//widget.h

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    Widget(QWidget *parent = 0);
    ~Widget(){}
};
 
#endif // WIDGET_H

//widget.cpp

#include "widget.h"
 
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    /* 创建控件 */
    QPushButton *btnClick      = new QPushButton("click me", this);
    QPushButton *btnBlock      = new QPushButton("block", this);
    QPushButton *btnUnblock    = new QPushButton("unblock", this);
    QPushButton *btnDisconnect = new QPushButton("disconnect", this);
 
    QGridLayout *pLayout = new QGridLayout();
    pLayout->addWidget(btnClick, 0, 0);
    pLayout->addWidget(btnBlock, 0, 1);
    pLayout->addWidget(btnUnblock, 0, 2);
    pLayout->addWidget(btnDisconnect, 0, 3);
    this->setLayout(pLayout);
 
    /* 信号槽 */
    connect(btnClick, &QPushButton::clicked, this, [=]()
    {
        qDebug() << "点击按钮";
    });
 
    connect(btnBlock, &QPushButton::clicked, this, [=]()
    {
        btnClick->blockSignals(true);
        btnBlock->setEnabled(false);
        btnUnblock->setEnabled(true);
    });
 
    connect(btnUnblock, &QPushButton::clicked, this, [=]()
    {
        btnClick->blockSignals(false);
        btnBlock->setEnabled(true);
        btnUnblock->setEnabled(false);
    });
 
    connect(btnDisconnect, &QPushButton::clicked, this, [=]()
    {
        disconnect(btnClick, &QPushButton::clicked, this, 0);
    });
 
}

//main.c

#include "widget.h"
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
 
    return a.exec();
}

结果:

 

1.按下"click me"按钮,窗口接收到"click me"按钮发出的clicked信号,打印"点击按钮"。

2.然后再按下"block",再次按下"click me"按钮,没有打印"点击按钮"。这是因为 "click me"按钮发出的信号被阻塞了,没有得到响应。

3.然后再按下"unblock"按钮,再次按下"click me"按钮,打印"点击按钮"。这是因为解除了"click me"按钮的信号阻塞。

4.最后按下"disconnect"按钮,此时按下"click me"按钮没有反应。这是因为解除了本窗口与"click me"按钮的clicked信号的连接。

文章转自博客园(ImreW):信号和槽 - ImreW - 博客园

本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓ 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt-信号和槽 的相关文章

随机推荐

  • 虚拟化、虚拟机等概念理解

    虚拟化 定义 是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机 在一台计算机上同时运行多个逻辑计算机 每个逻辑计算机可运行不同的操作系统 并且应用程序都可以在相互独立的空间内运行而不受影响 从而显著提高计算机的工作效率 软件 完全虚拟 V
  • Qt表格分页,跳转,首尾页

    简介 1 使用QTableWidget实现了首页 上下页切换 尾页 以及跳转 上代码 widget h ifndef WIDGET H define WIDGET H include
  • unity 使用vrtk4的插件 打包htv vive VR客户端包,手柄不生效

    背景 目的 u3d使用vrtk开发pico应用 vrtk是为了到时候无缝衔接后续要买的htc vive pro 2 先导入了tilia importer 也就是vrtk4 0 根据教程模块化使用功能 和pico官网下的 PICO Unity
  • Dom事件

    1 onclick 点击事件 2 ondbclick 双击事件 3 onmousedown 鼠标按下事件 4 onmouseup 鼠标松开事件 5 onmouseenter 鼠标移入事件 不支持冒泡 只触发一次 6 onmouseover
  • Linux 磁盘与文件系统管理(鸟哥私房菜)

    本文来自 http vbird dic ksu edu tw linux basic 0230filesystem php 第八章 Linux 磁盘与文件系统管理 系统管理员很重要的任务之一就是管理好自己的磁盘文件系统 每个分割槽不可太大也
  • JAVA用到的环境变量,JAVA_HOME、CLASSPATH、PATH

    Windows下JAVA用到的环境变量主要有3个 JAVA HOME CLASSPATH PATH JAVA HOME指向的是JDK的安装路径 如C JDK 1 4 2 在这路径下你应该能够找到bin lib等目录 值得一提的是 JDK的安
  • vue3学习笔记(1)script引入vue3实现简单应用

    Vue3专栏入口 目录 一 脚本引入简单使用 二 双向绑定的基本表现 一 脚本引入简单使用 script引入 简单使用实现数据渲染 div h1 counter num h1 div
  • 人工智能学习(一)newff函数介绍

    以下是matlab中的newff函数说明 不是neurolab中的newff 两者的参数不同 newff函数 指的是训练前馈网络的第一步是建立网络对象 实质是newff函数的参数 newff函数的格式为 net newff PR S1 S2
  • Linux服务器装mysql数据库并且连接数据库(详细教程)(阿里云)

    废话不多说 直接上教程 1 首先执行如下命令 更新YUM源 rpm Uvh http dev mysql com get mysql57 community release el7 9 noarch rpm 执行完上面命令后如果出现Peer
  • Verilog学习记录4——Verilog +: / -:语法

    Verilog 语法 看到这个语法的时候是在分析 IP AXI4 STREAM DATA FIFO的example时碰见的 然后查阅了资料 做出如下理解 变量的定义可以分为大端和小端 由于实际使用中变量常定义成大端 所以这里对小端不进行分析
  • 【华为OD机试】分糖果【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 小明从糖果盒中随意抓一把糖果 每次小明会取出一半的糖果分给同学们 当糖果不能平均分配时 小明可以选择从糖果盒中 假设盒中糖果足够 取出一个糖果或放回一个糖果 小明最少
  • VS-code出现注释乱码以及VS调试过程中出现汉字乱码问题

    文章目录 VS VS code 1 前言 2 方法 VS Notepad 方法 VS VS code 1 前言 Visual Studio Code 简称VS code 是如今我们常用的一款编辑器 但是可能一些用户会需要其他软件进行调试等
  • 一次线上生产系统内存泄漏排查与优化实践

    今天给大家分享一个我们之前基于dubbo开发一个线上系统时候遇到的内存泄漏生产问题的排查与优化实践经验 相信对于大家多看一些类似的案例 以后对于大家自己在线上系统遇到各种生产问题的时候 进行排查和优化的思路会有很大的启发 内存泄漏问题发生背
  • begin to drop messages due to rate-limiting

    对于syslog保存的日志会有很多重要信息 但是一旦打印的日志数量超过设置的阈值 就会丢掉 imuxsock pid 48 begin to drop messages due to rate limiting 这是在调试时不愿看到的 可以
  • 【论文笔记系列】AutoML:A Survey of State-of-the-art (上)

    之前已经发过一篇文章来介绍我写的AutoML综述 最近把文章内容做了更新 所以这篇稍微细致地介绍一下 由于篇幅有限 下面介绍的方法中涉及到的细节感兴趣的可以移步到论文中查看 论文地址 https arxiv org abs 1908 007
  • yolo 车辆测距+车辆识别+单目测距(双目测距)

    基于yolo目标检测算法实现的车前道路中的车辆和行人检测 并且可以估测出目标与本车之间的距离 一 视频展示 yolo车距1 订阅专栏获得源码 提供完整代码 无需看下文 二 单目测距原理 图中有一个车辆 且车辆在地面上 其接地点Q必定在地面上
  • 用KNN(K近邻算法)和ANN(人工神经网络)建立预测模型

    数据 输入 32 维的向量 输出一个值 有151组这样的数据 目的 用这样一组数据建立一个预测模型 输入32维的向量就能预测一个值 代码部分 1 导入工具包 在import pandas as pd import seaborn as sn
  • 机器学习算法Python实现:tfidf 特征词提取及文本相似度分类

    coding utf 8 本代码主要实现了对于商品名称根据tfidf提取特征词 然后基于已经训练好的word2vec模型 对每行商品的tfidf值大于某一阈值的特征词相似度匹配已经给定的商品类别 import jieba import ji
  • 有趣算法之C++函数模板

    C 函数模板 20200924 原文链接 https www runoob com w3cnote c templates detail html 原文正在慢慢理解中 模板是C 支持参数化多态的工具 使用模板可以使用户为类或者函数声明一种一
  • Qt-信号和槽

    一 Qt信号和槽机制 emit的使用 一 相关概念 1 信号 Signal 就是在特定情况下被发射的事件 例如PushButton 最常见的信号就是鼠标单击时发射的 clicked 信号 一个 ComboBox 最常见的信号是选择的列表项变