(9)Qt中信号与槽重载的解决方案

简介: 本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。

信号与槽重载的解决方案

一、通过函数指针解决

//信号
void (Me::*funchungury)() = &Me::hungury;
void (Me::*funchungury_QString)(QString) = &Me::hungury;
//槽
void (Me::*funceat)() = &Me::eat;
void (Me::*funceat_QString)(QString) = &Me::eat;

//有参连接
connect(me,funchungury_QString,me,funceat_QString);
//无参连接
connect(me,funchungury,me,funceat);

继续使用自定义信号时使用的父子窗口切换的案例:

/*
    SubWidget.h文件中添加一个openMainWindow(const QString&)重载信号
*/
#ifndef _SUBWIDGET_H_
#define _SUBWIDGET_H_
#include <QWidget>
#include <QPushButton>

class SubWidget : public QWidget
{
    Q_OBJECT
public:
    SubWidget(QWidget* parent = nullptr);
    ~SubWidget();
private:
    QPushButton* m_btn;
signals:
    void openMainWindow();                        //    自定义信号
    void openMainWindow(const QString&);        //    带参数的自定义信号
};

#endif
/*
    使用emit发送信号
*/
#include "SubWidget.h"

SubWidget::SubWidget(QWidget* parent)
    :QWidget(parent)
{
    resize(400, 400);
    setWindowTitle("子窗口");

    m_btn = new QPushButton("切换到父窗口", this);

    //使用emit发送信号
    connect(m_btn, &QPushButton::clicked, this, [=](){
        emit openMainWindow();
        emit openMainWindow(QString("我是重载的信号"));
    });
}

SubWidget::~SubWidget()
{

}
/*
    Widget.h文件中添加重载的槽函数funcSlot(const QString& msg);
*/
#ifndef _WIDGET_H_
#define _WIDGET_H_

#include <QWidget>
#include <QPushButton>
#include "SubWidget.h"

class SubWidget;
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget* parent = nullptr);
    ~Widget();
public slots:
    void funcSlot();                        //    不带参数的槽函数
    void funcSlot(const QString& msg);        //    带参数的槽函数
private:
    QPushButton* m_btn = nullptr;
    SubWidget* m_subWidget = nullptr;
};

#endif
#include"Widget.h"

Widget::Widget(QWidget* parent)
    :QWidget(parent)
{
    resize(640, 480);                                // 设置父窗口大小
    setWindowTitle("父窗口");                        // 设置父窗口标题

    m_btn = new QPushButton("切换到子窗口", this);
    m_subWidget = new SubWidget;

    //实现从父窗口切换到子窗口的效果
    connect(m_btn, &QPushButton::clicked,[=]() {
        this->hide();
        m_subWidget->show();
    });

    //实现从子窗口切换到父窗口的效果
    //使用函数指针的方式解决信号重载    槽重载
    void (SubWidget:: * signalFunc)() = &SubWidget::openMainWindow;
    void (SubWidget:: * signalFunc2)(const QString&) = &SubWidget::openMainWindow;

    void (Widget:: * slotFunc)() = &Widget::funcSlot;
    void (Widget:: * slotFunc2)(const QString&) = &Widget::funcSlot;

    connect(m_subWidget, signalFunc, this, slotFunc);            //    无参连接
    //connect(m_subWidget, signalFunc2, this, slotFunc2);            //    带参连接
}

Widget::~Widget()
{

}

//槽函数
void Widget::funcSlot()
{
    this->show();
    m_subWidget->hide();
}
//重载的带参数的槽函数
void Widget::funcSlot(const QString& msg)
{
    this->show();
    m_subWidget->hide();
    setWindowTitle(msg);
}

上面的案例中,有参数的连接会改变父窗口的标题,没有参数的连接不会改变父窗口的标题。

不带参数的连接:

带参数的连接:

二、通过Qt提供的重载类(QOverload)解决

//有参连接
connect(this,QOverload<QString>::of(&MyButton::hungury),
        this,QOverload<QString>::of(&MyButton::eat));
//无参连接
connect(this,QOverload<>::of(&MyButton::hungury),
        this,QOverload<>::of(&MyButton::eat));

直接使用QOverload类的方式解决父子窗口切换信号与槽重载的问题:

//使用QOverload的方式解决信号重载    槽重载
connect(m_subWidget, QOverload<>::of(&SubWidget::openMainWindow), 
    this, QOverload<>::of(&Widget::funcSlot));                            //    无参连接
connect(m_subWidget, QOverload<const QString&>::of(&SubWidget::openMainWindow),
    this, QOverload<const QString&>::of(&Widget::funcSlot));            //    带参连接

三、使用Qt4的方式解决

这种旧的信号与槽的连接方式在Qt6中是支持的, 但是不推荐使用, 因为这种方式在进行信号槽连接的时候, 信号和槽函数通过宏SIGNALSLOT转换为字符串类型。因为信号和槽函数的转换是通过宏来进行转换的,因此传递到宏函数内部的数据不会被进行检测, 如果使用者传错了数据,编译器也不会报错,但实际上信号槽的连接已经不对了,只有在程序运行起来之后才能发现问题,而且问题不容易被定位。

Me m;
// Qt4处理方式  注意不要把信号与槽的名字写错了,因为是转为字符串写错了不会报错,但是连接会失败
connect(&m, SIGNAL(eat()), &m, SLOT(hungury()));
connect(&m, SIGNAL(eat(QString)), &m, SLOT(hungury(QString)));

// Qt5处理方式
connect(&m, &Me::eat, &m, &Me::hungury);    // error:no matching member function for call to 'connect'

直接使用Qt4的方式解决父子窗口切换信号与槽重载的问题:

//使用Qt4的方式解决信号重载    槽重载
connect(m_subWidget, SIGNAL(openMainWindow()),
    this, SLOT(funcSlot()));
connect(m_subWidget, SIGNAL(openMainWindow(const QString&)),
    this, SLOT(funcSlot(const QString&)));

总结

  • Qt4的信号槽连接方式使用了宏函数, 宏函数对用户传递的信号槽不会做错误检测, 容易出bug

  • Qt5的信号槽连接方式, 传递的是信号槽函数的地址, 编译器会做错误检测, 减少了bug的产生

  • 当信号槽函数被重载之后, Qt4的信号槽连接方式不受影响,Qt6中需要给被重载的信号或者槽定义函数指针或者使用QOverload

相关文章
|
5月前
|
存储 安全 编译器
【Qt 底层机制之信号和槽 】深入探究Qt信号和槽背后的原理
【Qt 底层机制之信号和槽 】深入探究Qt信号和槽背后的原理
1627 4
|
5月前
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
74 0
|
5月前
|
存储 API C++
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
450 0
|
5月前
|
安全 编译器 开发者
【Qt 学习笔记】Qt信号和槽的其他说明及Lambda表达式
【Qt 学习笔记】Qt信号和槽的其他说明及Lambda表达式
165 0
|
3天前
(8)Qt中的自定义信号
本文介绍了如何在Qt框架中创建和使用自定义信号,并通过一个父子窗口切换的示例来展示自定义信号的实现和应用。
19 3
(8)Qt中的自定义信号
|
4月前
|
安全 C++ Windows
Qt信号与槽机制
Qt信号与槽机制
47 1
|
5月前
|
算法 Ubuntu Linux
Linux Qt cannot find -lGL错误完美解决方案(亲测有效)
Linux Qt cannot find -lGL错误完美解决方案(亲测有效)
298 1
|
2月前
|
程序员 C++
【Qt】信号与槽(下)
【Qt】信号与槽(下)
|
2月前
|
Linux C++
【Qt】信号与槽(上)
【Qt】信号与槽(上)
【Qt】信号与槽(上)
|
2月前
【qt】有点意思的信号与槽
【qt】有点意思的信号与槽
16 0