信号信号槽

三、信号槽

  1. 概念

信号和槽是两种函数,这是Qt在C++基础上新增的特性,类似于其他技术中的回调的概念。

信号槽通过程序员提前设定的“约定”,可以实现对象之间的通信,有两个先决条件。

  • 通信的对象都是在QOBject类中派生出来的。

QOBject类是Qt所有类型的基类。

  • 类中要有Q_OBJECT宏。

  1. 函数原型

信号槽需要在使用进行“约定”。这个约定也称为连接。

【例子】:如果新周考试考100分,那么宵宾请新周吃饭。

// 参数1:发射者,表示因发起的对象【新周】
// 参数2:信号函数,表示因发起的动作【考100】
// 参数3:接收者,表示果发起的对象【宵宾】
// 参数4:槽函数,表示果发起的动作【请吃饭】
connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)[static]

  1. 实现

为了学习,把信号槽分为三种实现的方式。

  • 自带信号→自带槽
  • 自带信号→自定义槽
  • 自定义信号

3.1 自带信号→自带槽

这种连接方式是最简单的,因为信号函数和槽函数都是Qt内置的,只需要在文档中查询出函数后,使用connect函数连接即可。

【例子】:点击按钮,关闭窗口。

// 点击按钮,发射此信号
void QAbstractButton::​clicked(bool checked = false)[signal]

// 关闭窗口槽函数
bool QWidget::​close()[slot]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn; // 成员变量
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{// 设置窗口的宽高resize(500,500);    btn = new QPushButton("关闭",this);// 设置按钮位置
    btn->move(200,250);// 连接信号槽【点击按钮,关闭窗口】// 参数1:按钮对象// 参数2:点击信号函数clicked// 参数3:窗口对象// 参数4:关闭窗口槽函数closeconnect(btn,SIGNAL(clicked()),this,SLOT(close()));
}Dialog::~Dialog()
{// 堆内存回收
    delete btn;
}

3.2 自带信号→自定义槽

Qt不可能内置所有执行的动作代码,特别是一些复杂的动作,需要开发者手动编写槽函数,这种方式是所有连接方式中使用最多的。

槽函数实际上是一种特殊的成员函数,在声明的时候权限的作用主要是修饰其作为普通成员函数的使用效果,不影响信号槽的连接效果。

【例子】:点击按钮,向右边和下边移动窗口10个相似,同时输出当前窗口的坐标。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);
    ~Dialog();private:QPushButton *btn; // 成员变量private slots:
    void mySlot(); // 小驼峰命名:第一个单词小写,其他单词首字母大写};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口的宽高
    resize(500,500);    btn = new QPushButton("关闭",this);
    // 设置按钮位置
    btn->move(200,250);
    // 连接信号槽
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}// 自定义槽函数实现
void Dialog::mySlot()
{
    // 先获取当前的坐标
    int x = this->x();
    int y = this->y();    // 移动坐标位置
    move(x+10,y+10);    // 输出当前位置
    qDebug() << x+10 << y+10;
}Dialog::~Dialog()
{
    // 堆内存回收
    delete btn;
}

3.3 自定义信号

为了讲解,强行使用自定义信号,并非问题的最优解,主要学习写法。

信号函数是一种非常特殊的函数,因为只有声明,没有定义。即没有函数体,因此无法调用,只能使用emit关键字发射。

【例子】:点击按钮,关闭窗口。

3.1 的信号连接方式。

本节中强行在中间加一层自定义信号的转发过程。

上图中→表示信号槽连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QPushButton *btn;private slots:
    void mySlot();    // 自定义信号
signals:
    void mySignal();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 创建按钮对象
    btn = new QPushButton("关闭",this);
    btn->move(100,150);    // 信号槽连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));    // 第二次槽函数连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}Dialog::~Dialog()
{
    delete btn;
}

4、信号槽传参

【例子】点击按钮,按钮上显示点击的次数。

 QPushButton的按钮文字属性为text : QString,可以使用setter更改按钮文字。

// 设置按钮显示的文字
// 显示的文字,QString类型
void	setText(const QString & text)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    QPushButton *btn;private slots:
    void mySlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}Dialog::~Dialog()
{
    delete btn;
    delete ui;
}void Dialog::mySlot()
{
    // 静态局部变量
   static int count = 0;
   count++;
   // 类型转换 int → QString
   QString text = QString::number(count);   // 更改按钮文字
   btn->setText(text);}

把上面的案例强行改为信号槽传参:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    QPushButton *btn;private slots:
    void mySlot();
    void mySlot2(int); // 与mySignal(int)连接的自定义槽函数
signals:
    void mySignal(int); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(int)),
            this,SLOT(mySlot2(int)));
}Dialog::~Dialog()
{
    delete btn;
    delete ui;
}void Dialog::mySlot()
{
    // 静态局部变量
    static int count = 0;
    count++;    emit mySignal(count);
}void Dialog::mySlot2(int count)
{
    // 类型转换 int → QString
    QString text = QString::number(count);    // 更改按钮文字
    btn->setText(text);
}

需要注意的是:

  • 理论上可以传递多个参数,建议最多写两个参数,多了会很冗余。如果非得传递多个参数,可以定义成一个类,传递对象。
  • 信号的参数个数必须大于等于槽函数参数个数。
  • 信号的参数类型要与槽的参数相匹配。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Demo
{
public:
    int a = 10;
    int b = 20;
    double c = 3.23;
    float d = 1.1;
};class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn;private slots:
    void mySlot();  // 自定义槽函数
    void mySlot2(const Demo &); // 与mySignal(int)连接的自定义槽函数signals:
    void mySignal(const Demo &); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn = new QPushButton("0",this);
    btn->move(150,150);connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));connect(this,SIGNAL(mySignal(const Demo &)),this,SLOT(mySlot2(const Demo &)));
}void Dialog::mySlot()
{Demo demo;// 发射带参数的自定义信号函数
    emit mySignal(demo);
}void Dialog::mySlot2(const Demo &demo)
{qDebug() << demo.a;qDebug() << demo.b;qDebug() << demo.c;qDebug() << demo.d;
}Dialog::~Dialog()
{
    delete btn;
}

5、对应关系

5.1 一对多

一对多指的是一个信号可以连接多个槽函数。

对于一对多的连接关系,可以合并为一对一,因为槽函数也是一个成员函数,可以整合到一个槽函数中进行连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:
    QPushButton *btn1; // 一对多
    QPushButton *btn2; // 一对一private slots:void mySlot1();void mySlot2();void mySlot3();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn1 = new QPushButton("一对多",this);
    btn1->move(200,200);// 一对多的优势就是可以灵活处理每个对应关系// 例如可以断开某个信号槽的连接// 断开连接的函数与连接槽函数一样,只需要在函数名称前面加disdisconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));// 一对多connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));// 一对一
    btn2 = new QPushButton("一对一",this);
    btn2->move(200,250);connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot3()));disconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));
}Dialog::~Dialog()
{}void Dialog::mySlot1()
{qDebug() << "A" ;
}
void Dialog::mySlot2()
{qDebug() << "B" ;
}void Dialog::mySlot3()
{mySlot1();mySlot2();
}

5.2 多对一

多对一指的是多个信号连接同一个槽函数,多对一的问题在于槽函数无法直接判断那个信号触发的槽函数调用,但是可以通过sender函数在槽函数中获得发射者对象,通过对象的比对判断来源。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();
private:
    QPushButton *btn1;
    QPushButton *btn2;private slots:// 多对一的槽函数void btnClickedSlot();};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn1 = new QPushButton("多对一A",this);
    btn1->move(200,200);    btn2 = new QPushButton("多对一B",this);
    btn2->move(200,250);// 多对一connect(btn1,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));connect(btn2,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{delete btn1;delete btn2;
}void Dialog::btnClickedSlot()
{if(btn1 == sender()){qDebug() << "A" ;}else if(btn2 == sender()){qDebug() << "B" ;}else{qDebug() << "对象错误" ;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/485638.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】顺序表实现的层层分析!!

关注小庄 顿顿解馋◍˃ ᗜ ˂◍ 引言&#xff1a;本篇博客我们来认识数据结构其中之一的顺序表&#xff0c;我们将认识到什么是顺序表以及顺序表的实现&#xff0c;请放心食用~ 文章目录 一.什么是顺序表&#x1f3e0; 线性表&#x1f3e0; 顺序表 二.顺序表的实现&#x1f3e0…

2024年1月京东洗衣机行业数据分析:TOP10品牌销量销额排行榜

鲸参谋监测的京东平台1月份洗衣机市场销售数据已出炉&#xff01; 根据鲸参谋电商数据分析平台显示&#xff0c;今年1月份&#xff0c;京东平台上洗衣机的销量约160万件&#xff0c;环比上个月增长约42%&#xff0c;同比去年下滑7%&#xff1b;销售额约28亿元&#xff0c;环比…

四、矩阵的分类

目录 1、相等矩阵 2、同形矩阵 3、方阵&#xff1a; 4、负矩阵、上三角矩阵、下三角矩阵&#xff1a; 5、对角矩阵&#xff1a;是方阵 ​编辑7、单位矩阵&#xff1a;常常用 E或I 来表示。它是一个方阵 8、零矩阵&#xff1a; 9、对称矩阵&#xff1a;方阵 1、相等矩阵 …

常见的芯片行业ERP:SAP Business One ERP系统

在现代企业管理中&#xff0c;企业资源规划(ERP)系统已成为不可或缺的工具。特别是在高度复杂和竞争激烈的芯片行业中&#xff0c;一款高效、全面的ERP系统更是助力企业实现精细管理、提升竞争力的关键。SAP Business One ERP系统便是其中一款备受推崇的选择。 SAP Business On…

电气机械5G智能工厂数字孪生可视化平台,推进电气机械行业数字化转型

电气机械5G智能工厂数字孪生可视化平台&#xff0c;推进电气机械行业数字化转型。随着科技的不断发展&#xff0c;数字化转型已经成为各行各业发展的重要趋势。电气机械行业作为传统制造业的重要组成部分&#xff0c;也面临着数字化转型的挑战和机遇。为了更好地推进电气机械行…

MYSQL-入门

一.安装和连接 1.1 安装 mysql安装教程&#xff1a; 2021MySql-8.0.26安装详细教程&#xff08;保姆级&#xff09;_2021mysql-8.0.26安装详细教程(保姆级)_mysql8.0.26_ylb呀的博客-cs-CSDN博客 workbench安装&#xff1a; MySQL Workbench 安装及使用-CSDN博客 1.2 配…

数据结构2月19日

题目&#xff1a;顺序表作业 代码&#xff1a; 功能区&#xff1a; #include <stdio.h>#include <stdlib.h>#include "./d2191.h"SeqList* create_seqList(){SeqList* list (SeqList*)malloc(sizeof(SeqList));if(NULL list){return NULL;}list->p…

22-树-二叉树的后序遍历

这是树的第22篇算法&#xff0c;力扣链接。 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 我们来回忆一下后续遍历逻辑&#xff1a; 后序遍历 (Postorder Traversal) …

为什么选择OV证书以及如何申请?

在信息化高度发达的今天&#xff0c;对于企业而言&#xff0c;在线交易、数据传输的安全性直接影响到品牌形象和用户信任度。在这个背景下&#xff0c;SSL/TLS证书中的组织验证&#xff08;Organization Validated&#xff0c;简称OV&#xff09;证书因其独特的安全性和权威性&…

QT中调用python

一.概述 1.Python功能强大&#xff0c;很多Qt或者c/c开发不方便的功能可以由Python编码开发&#xff0c;尤其是一些算法库的应用上&#xff0c;然后Qt调用Python。 2.在Qt调用Python的过程中&#xff0c;必须要安装python环境&#xff0c;并且Qt Creator中编译器与Python的版…

如何理解跨境ERP定制中的技术要点与挑战?

在跨境电商领域日益竞争激烈的今天&#xff0c;企业需要依靠先进的ERP系统来实现信息管理、数据整合和业务流程优化。而针对不同国家和地区的特殊需求&#xff0c;跨境ERP定制越来越成为企业必须面对的挑战。本文将深入探讨跨境ERP定制中的技术要点与挑战&#xff0c;帮助企业更…

缓存篇—缓存雪崩

什么是缓存雪崩 通常我们为了保证缓存中的数据与数据库中的数据一致性&#xff0c;会给 Redis 里的数据设置过期时间&#xff0c;当缓存数据过期后&#xff0c;用户访问的数据如果不在缓存里&#xff0c;业务系统需要重新生成缓存&#xff0c;因此就会访问数据库&#xff0c;并…