QT:信号和槽02

典型实例

在主界面中创建一个对话框,在这个对话框中可以输入姓名、编号,当单击"确定"按钮时,关闭对话框,然后将输入的编号通过信号发射出去,最后在主界面中接收该信号并且显示编号数值






项目建立完成后,向项目中添加新文件,模板选择Qt分类中的"Qt设计器界面类"​,界面模板选择Dialog without Buttons,类名设置为MyDialog。



在mydialog.h文件中添加代码来声明一个信号:

c 复制代码
#ifndef MYDIALOG_H
#define MYDIALOG_H

#include <QDialog>
#include<string>
namespace Ui {
class MyDialog;
}

class MyDialog : public QDialog
{
    Q_OBJECT

public:
    explicit MyDialog(QWidget *parent = nullptr);
    ~MyDialog();

private:
    Ui::MyDialog *ui;

signals:
    void dlgReturn(std::string, int);//声明信号
};

#endif // MYDIALOG_H

声明一个信号要使用signals关键字,在signals前面不能用public、private或protected等关键字,因为信号默认是public函数,可以从任何地方进行发射,但是建议只在声明该信号的类及其子类中发射该信号。信号只用声明,不需要也不能对它进行定义实现。还要注意,信号没有返回值,只能是void类型的。因为只有QObject类及其子类派生的类才能使用信号和槽机制,这里的MyDialog类继承自QDialog类,QDialog类又继承自QWidget类,QWidget类是QObject类的子类,所以这里可以使用信号和槽。另外,使用信号和槽还必须在类定义的最开始处添加Q_OBJECT宏。

双击mydialog.ui文件进入设计模式,在界面中添加一个Spin Box部件和一个Push Button部件换位一个lineEdit,将pushButton的显示文本修改为"确定"​。

SpinBox用于整数的显示与输入,一般显示为十进制,也可以显示二进制和十六进制的数,而且可以在显示框增加前缀和后缀

lineEdit 输入姓名使用

转到pushButton的单击信号clicked()对应的槽,更改如下。

c 复制代码
void MyDialog::on_pushButton_clicked()
{
    int index = ui->spinBox->value();
    std::string name = ui->lineEdit->text().toStdString();
    emit dlgReturn(name,index); //获取输入值
    qDebug() << " index :" <<  index << " name :" << name;
}

击"确定"按钮便可以获取spinBox部件中的数值,然后使用自定义的信号将其作为参数发射出去。发射一个信号要使用emit关键字,例如这里发射了dlgReturn()信号。

connect()函数的最后一个参数type表明了关联的方式,由Qt::ConnectionType枚举类型指定,其默认值是Qt::AutoConnection,还有其他几个选择,在MyDialog类中使用emit发射信号之后,就会立即执行槽,只有等槽执行完以后,才会执行emit语句后面的代码。这里可以将这个参数改为Qt::QueuedConnection,这样在执行完emit语句后便会立即执行其后面的代码,而不管槽是否已经执行,可以通过"应用程序输出"窗口的信息查看效果。

然后到widget.h文件中添加自定义槽的声明:

c 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<string>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;

private slots:
    void showindex(const std::string& name, int index);
};
#endif // WIDGET_H

下面打开widget.ui文件,向界面上拖入一个Label部件,更改其文本为"用户信息:​"​。

然后进入widget.cpp文件中,添加头文件#include "mydialog.h",再在构造函数中添加如下代码。

c 复制代码
#include "widget.h"
#include "ui_widget.h"
#include "mydialog.h"
#include <QString>
#include <QDebug>
#include <String>

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

    MyDialog *dlg = new MyDialog(this);

    connect(dlg, SIGNAL(dlgReturn(const std::string&, int)),
            this, SLOT(showindex(const std::string&, int)));

    dlg->show();
}

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

void Widget::showindex(const std::string& name, int index)
{
    // 将std::string转换为QString
    QString qName = QString::fromStdString(name);
    ui->label_2->setText(tr("%1").arg(qName));
    ui->label_3->setText(tr("%1").arg(index));
    qDebug() << "name: " << name ;
    qDebug() << "index: " << index ;
}

这里创建了一个MyDialog实例dlg,并且使用Widget作为父部件。然后将MyDialog类的dlgReturn()信号与Widget类的showValue()槽进行关联。

升级一下

将dlg定义为类成员,实现的功能是点击后dlg会关闭

widget.cpp

c 复制代码
#include "widget.h"
#include "ui_widget.h"
#include "mydialog.h"
#include <QString>
#include <QDebug>
#include <String>

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

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

void Widget::showdlg()
{
    dlg = new MyDialog(this);

    connect(dlg, SIGNAL(dlgReturn(const std::string&, int)),
            this, SLOT(showindex(const std::string&, int)));

    dlg->show();
}


void Widget::showindex(const std::string& name, int index)
{
    // 将std::string转换为QString
    QString qName = QString::fromStdString(name);
    ui->label_2->setText(tr("%1").arg(qName));
    ui->label_3->setText(tr("%1").arg(index));
    qDebug() << "name: " << name ;
    qDebug() << "index: " << index ;
    dlg->close();

}

widget.h

c 复制代码
#ifndef WIDGET_H
#define WIDGET_H
#include "mydialog.h"
#include <QWidget>
#include<string>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    void showdlg();

private:
    Ui::Widget *ui;
    MyDialog *dlg;

private slots:
    void showindex(const std::string& name, int index);
};

#endif // WIDGET_H

总结

这里实现了自己定义类,自己声明信号,关联槽函数。

注意

●需要继承自QObject类或其子类。

●在类定义的最开始处私有部分添加Q_OBJECT宏。

●槽中参数的类型要和信号参数的类型相对应,且不能比信号的参数多。

●信号只用声明,没有定义,且返回值为void类型。

●connect()函数时,信号和槽的参数只能有类型,不能有变量名

●使用emit发射信号

connect()函数的使用方法

1、自动关联

2、常规使用

3、自己定义信号

2、lamda函数

cpp 复制代码
QObject::connect(sender, &Sender::signal, [=](){
    // 在这里编写需要执行的代码
});

参考

《零基础学Ot 6编程》

相关推荐
知无不研1 分钟前
lambda表达式的原理和由来
java·开发语言·c++·lambda表达式
lili-felicity4 分钟前
CANN多模型并发部署与资源隔离
开发语言·人工智能
小龙报8 分钟前
【51单片机】深度解析 51 串口 UART:原理、配置、收发实现与工程化应用全总结
c语言·开发语言·c++·stm32·单片机·嵌入式硬件·51单片机
qq_5324535316 分钟前
使用 Three.js 构建沉浸式全景图AR
开发语言·javascript·ar
浅念-18 分钟前
C语言——动态内存管理
c语言·开发语言·c++·笔记·学习
草履虫建模6 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq8 小时前
分布式系统安全通信
开发语言·c++·算法
学嵌入式的小杨同学9 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
Re.不晚9 小时前
Java入门17——异常
java·开发语言
精彩极了吧9 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合