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编程》

相关推荐
用户805533698035 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner5 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz10 天前
QML Hello World 入门示例
qt
xcyxiner13 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner14 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript