百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

信号和槽 信号和槽是什么

liebian365 2024-11-12 13:09 19 浏览 0 评论

一、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资料领取→「链接」

(二)注意点

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):https://www.cnblogs.com/imreW/p/17099568.html

Qt资料领取→Qt资料领取(视频教程+文档+代码+项目实战)

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: