当前位置: 首页 > news >正文

【QT】QT中的信号与槽

QT中的信号与槽

  • 一、信号与槽函数的作用
  • 二、如何关联信号与槽函数
    • 1、借助集成开发环境,右键转到槽函数
      • 示例代码:
    • 2、调用connect函数手动关联信号与槽函数
  • 三、扩展
  • 四、总结信号与槽的特点
    • 1、一个类如果要使用信号以及槽函数,那么该类的定义中必须加上Q_OBJECT宏定义
    • 2、同一个槽函数,可以被不同对象的信号关联
    • 3、同一个信号,可以关联不同的槽函数
    • 4、信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)
    • 5、信号带参数,槽函数可以带参数,也可以不带参数
  • 五、获取信号的发送者
    • 示例代码:
  • 六、自定义信号,发送信号
    • 示例代码:

一、信号与槽函数的作用

用来在组件和组件,组件和窗口之间通信

  • 信号:QT中给每个组件都定义了信号,每个信号都有它特定的触发条件(QT助手查询到每个信号的触发条件)

QT中所有的信号,本质上都是个函数,信号只有声明,没有源代码

比如:以按钮为例,常用的信号如下
       [signal] void QAbstractButton::clicked(bool checked = false)  //当按钮按下去,然后松开的时候自动触发这个信号
       [signal] void QAbstractButton::released()  //按钮松开会触发该信号
       [signal] void QAbstractButton::pressed()   //按钮按下去触发该信号
  • 槽函数:当某个信号触发的时候,跟这个信号对应的槽函数会被自动调用执行

二、如何关联信号与槽函数

关联信号与槽函数:就是使选择的信号跟槽函数形成一一对应关系

1、借助集成开发环境,右键转到槽函数

  • 头文件中会自动生成槽函数的声明
private slots:   //声明了一个私有的槽函数
	void on_pushButton_clicked();  //槽函数的原型声明
  • 在源码.cpp文件中自动生成的槽函数的定义

on_对象的名字_信号的名字();

示例代码:

// login.cpp
#include "loginwin.h"
#include "ui_loginwin.h"
#include <QLabel>
#include <QFont>
#include <QLineEdit>
#include <QPushButton>
#include <iostream>
#include <QDebug>
using namespace std;
loginwin::loginwin(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::loginwin)
{
    ui->setupUi(this);
    //通过写代码把登录界面的ui做出来
    //第一步:标签
    //父窗口:这个组件(控件)等一会在哪个窗口上显示,这个窗口就是父窗口
    QLabel *lb1=new QLabel("学生管理系统",this);
    //设置按钮的坐标,宽高
    /*
        规律:任何组件,属性都有对应的设置方法,方法的名字统一叫做setxxx()
             比如:属性geometry --》对应的方法setGeometry()
    */
    lb1->setGeometry(200,10,400,100);
    QFont myfont("楷体",24);
    lb1->setFont(myfont);
    //设置样式
    lb1->setStyleSheet("color:rgb(255,0,0);");
    //第二步:两个单行输入框
    QLineEdit *le1=new QLineEdit(this);
    QLineEdit *le2=new QLineEdit(this);
    //设置坐标,宽高
    le1->setGeometry(220,130,300,50);
    le2->setGeometry(220,220,300,50);
    //设置默认提示文字
    le1->setPlaceholderText("请输入用户名");
    le2->setPlaceholderText("请输入密码");
    //设置用户名,密码位数
    le1->setMaxLength(8);
    le2->setMaxLength(8);
    //设置密码隐藏
    le2->setEchoMode(QLineEdit::Password);
    //设置样式
    le1->setStyleSheet("border:2px solid#ff0000;");
    le2->setStyleSheet("border:2px solid#ff0000;");
    //设置字体
    le1->setFont(myfont);
    le2->setFont(myfont);
    //第三步:两个按钮
    QPushButton *bt1=new QPushButton("登录",this);
    QPushButton *bt2=new QPushButton("注册",this);
    bt1->setFont(myfont);
    bt2->setFont(myfont);
    //设置坐标,宽高
    bt1->setGeometry(200,300,100,50);
    bt2->setGeometry(450,300,100,50);

    //给主窗口设置边框图片
    this->setStyleSheet("QMainWindow{border-image: url(C:/Users/Administrator/Desktop/share/4.jpeg);}");
}

loginwin::~loginwin()
{
    delete ui;
}

//跟登录按钮有关的槽函数
//槽函数的定义--》代码由程序员来编写
void loginwin::on_pushButton_clicked()
{
    //C++的输出
    //cout<<"登录按钮被点击(按下去,然后松开)"<<endl;
    //cout<<"loginbt clicked"<<endl;
    //QT特有的输出,自动换行,不需要回车
    qDebug()<<"登录按钮被点击(按下去,然后松开)";
}

//跟release信号有关的槽函数
void loginwin::on_pushButton_released()
{
    qDebug()<<"登录按钮松开";
}
//跟pressed信号有关的槽函数
void loginwin::on_pushButton_pressed()
{

}

// login.h
#ifndef LOGINWIN_H
#define LOGINWIN_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class loginwin; }
QT_END_NAMESPACE

class loginwin : public QMainWindow
{
    Q_OBJECT

public:
    loginwin(QWidget *parent = nullptr);
    ~loginwin();

//翻译qt程序--》uic和moc(qt程序除了c++代码之外还有qt特有的(例如信号与槽),所有需要翻译成c++代码)
//slots是QT特有的关键字,C++中没有
private slots:  //声明私有的槽函数
    //在源码.cpp文件中自动生成的槽函数的定义,命名有规律
    //on_对象的名字_信号的名字();
    void on_pushButton_clicked(); //槽函数的原型声明

    void on_pushButton_released(); //槽函数的原型声明

    void on_pushButton_pressed();  //槽函数的原型声明

private:
    Ui::loginwin *ui;
};
#endif // LOGINWIN_H

2、调用connect函数手动关联信号与槽函数

有些场合无法右键转到槽(比如:按钮不是ui设计师拖过去,而是通过写代码new出来)

  • 写法1:
connect(QObject *sender, PointerToMemberFunction signal,QObject *receiver, PointerToMemberFunction method)
  • 写法2
connect(发送者指针,&类的名字::信号的名字,接收者,&类的名字::槽函数)
                    参数:sender --》信号的发送者,指针
                          signal --》发送什么信号
                          receiver --》信号的接收者
                          method --》需要调用的槽函数
                                    槽函数命名时候,可以跟自动生成的槽函数命名规律保持一致,也可以自行单独命名
比如:connect(ui->handlebt,SIGNAL(clicked(bool)),this,SLOT(fun())); //关联了handlebt这个按钮的clicked信号和槽函数fun()

QT使用技巧:头文件中声明了函数,右键选择refactor,可以在.cpp生成函数的定义

三、扩展

QObject --》QT中所有类的基类
作为形参的好处:实参可以传递任何类型(因为QT中所有的类都是QObject的子类)

四、总结信号与槽的特点

1、一个类如果要使用信号以及槽函数,那么该类的定义中必须加上Q_OBJECT宏定义

Q_OBJECT:QT把它称为元对象系统,作用支持信号与槽这种机制

在这里插入图片描述

2、同一个槽函数,可以被不同对象的信号关联

// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 同一个槽函数,可以被不同对象的信号关联
    connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btn()));
    connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btn()));
    connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btn()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::btn()
{
    qDebug()<<"按钮按下";
}
//===========================================//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void btn();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

3、同一个信号,可以关联不同的槽函数

槽函数的调用顺序跟关联的先后顺序一致,先关联的先调用

// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //同一个信号,可以关联不同的槽函数
    //槽函数的调用顺序关联的先后顺序一致,先关联的先调用
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn2()));
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn1()));
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn3()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::btn1()
{
    qDebug()<<"按下btn1";
}

void MainWindow::btn2()
{
    qDebug()<<"按下btn2";
}

void MainWindow::btn3()
{
    qDebug()<<"按下btn3";
}
//=======================================================//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void btn1();
    void btn2();
    void btn3();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

4、信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)

信号的接收者跟槽函数之间必须是所属关系(接收者对应的类里面必须有这个槽函数)

// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //自己手动管理按钮的clicked信号跟自己写的槽函数
    /*
        信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)
        信号的接收者跟槽函数之间必须是所属关系(接收者对应的类里面必须有这个槽函数)
    */
    //错误1:信号发送者跟信号之间不是所属关系
    //connect(ui->pushButton,SIGNAL(textChanged(QString)),this,SLOT(fun()));
    //错误2:信号接收者跟槽函数之间不是所属关系
    //connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(myfun()));
    connect(ui->pushButton,SIGNAL(clicked()),ui->lineEdit,SLOT(fun()));
}

MainWindow::~MainWindow()
{
    delete ui;
}
//自己手写的槽函数
void MainWindow::fun()
{
    qDebug()<<"按钮被点击了";
}

 // mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    //自己手写槽函数,命名可以跟右键转到槽一样的命名,也可以随意命名
    void fun();
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

5、信号带参数,槽函数可以带参数,也可以不带参数

区别:

  • 槽函数带参数,参数必须跟信号保持一致,表示槽函数接收信号传递过来的参数
  • 槽函数不带参数,表示不接收信号传递过来的参数

注意:

  • 如果信号没有任何参数,此时槽函数也不可以有任何参数
  • 信号带了参数,connect写的时候不要写参数的名字,只需要写参数的类型
  • 槽函数带了参数,connect写的时候不要写参数的名字,只需要写参数的类型

五、获取信号的发送者

作用:当多个组件对象共用一个槽函数的时候,程序员需要知道是哪个组件对象触发的信号,此时就要获取信号的发送者

QObject *sender() const
           返回值:返回一个指针,该指针指向信号的发送者
QT中转换函数
    qobject_cast(QObject *object)  //把父类的指针转换成子类地址

示例代码:

//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 同一个槽函数,可以被不同对象的信号关联
    connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btn()));
    connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btn()));
    connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btn()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::btn()
{
//    qDebug()<<"按钮按下";
    // 获取信号的发送者,并判断哪个按钮被按下
    QObject *is_sender = sender();
    if(is_sender == ui->btn1)
        qDebug()<<"按钮1按下";
    else if(is_sender == ui->btn2)
        qDebug()<<"按钮2按下";
    else if(is_sender == ui->btn3)
        qDebug()<<"按钮3按下";

    // QT中转换函数的使用
    QPushButton *btn = qobject_cast<QPushButton *>(is_sender);
    btn->setStyleSheet("background-color:rgb(0,255,0);");
}

// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void btn();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

六、自定义信号,发送信号

//自定义信号语法格式
     signals:
             // 自定义信号;
             void mysignal(参数)//参数的类型个数依据需要自行添加
//发送信号
     //注意注意注意:自定义的信号必须程序员主动调用emit发送,不能自动触发的
             emit mysignal(实参);

示例代码:

// 第一个界面:mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "info_win.h"
#include <QString>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}
// 登录按钮的槽函数
void MainWindow::on_pushButton_clicked()
{
    // 获取输入的用户名和密码
    QString account = ui->lineEdit->text();
    QString pswd = ui->lineEdit_2->text();

    if(account == "aaa" && pswd == "123")
    {
        //创建第二个界面对象,必须传递this指针(把第一个界面的地址传给第二个界面)
        info_win *info_w = new info_win(this);
        // 将第一个界面的账号和密码传递给第二个界面 --信号发送
        connect(this, SIGNAL(sendSign(QString, QString)), info_w, SLOT(recvSlot(QString, QString)));
        emit sendSign(account, pswd);
        qDebug()<<"第一界面的地址是"<<this;
        // 显示第二个界面
        info_w->show();
        this->hide();
    }
    else
    {
        qDebug()<<"账号或密码错误,重新输入";
    }
}

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals: //自定义信号
    void sendSign(QString, QString);

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

相关文章:

  • LabVIEW液压控制系统开发要点
  • 异步加载+内存分析
  • linux内核`fixmap`和`memblock`有什么不同?
  • P2Rank网页端:预测蛋白结合口袋+vina分子对接
  • 力扣经典算法篇-6-轮转数组
  • C++ short类型的输入如何转换十进制
  • Kafka简要介绍与快速入门示例
  • java对接oracle存储过程基本知识(附Demo)
  • 设计模式 行为型设计模式
  • 记录关于Unitask的一些基础使用
  • Time spent invoking a CUDA kernel
  • 【Linux】系统文件的权限管理
  • open3d教程 (二)点云的读写
  • 常用天然地震链接
  • 【JAVA】十、基础知识“类和对象”干货分享~(一)
  • 香港理工视觉语言模型赋能智能制造最新综述!基于视觉语言模型的人机协作在智能制造中的应用
  • secure keyboard entry is enabled because another app has turned it on.
  • 阿里通义千问发布全模态开源大模型Qwen2.5-Omni-7B
  • 鸿蒙阔折叠Pura X外屏开发适配
  • MySQL的备份及还原
  • 人民日报:不能层层加码,要层层负责
  • 陈龙带你观察上海生物多样性,纪录片《我的城市邻居》明播出
  • 益阳通报“河水颜色异常有死鱼”:未发现排污,原因待鉴定
  • 波兰总统选举第一轮投票结束,出口民调显示将进入第二轮投票
  • 上海这场有温度的“人才集市”,为更多人才搭建“暖心桥”
  • 雅安市纪委监委回应黄杨钿甜耳环事件:相关政府部门正在处理