• Qt中的单例模式



    Chapter1 Qt中的单例模式

    原文链接:https://blog.csdn.net/baidu_18624493/article/details/130573407

    一、什么是单例模式?

        单例模式是一种创建型设计模式,用于确保类只有一个实例存在,并提供全局访问点以便于其他对象获取该实例。
    
        在单例模式中,类只能实例化一次,并提供了一个静态方法或全局访问点来获取该实例。这样可以确保在整个应用程序中只有一个实例存在,并且可以通过该实例进行操作和访问。
    
    • 1
    • 2
    • 3

    单例模式的特点包括:

    单一实例:单例模式确保类只有一个实例存在。

    全局访问点:通过静态方法或全局访问点获取单例对象,可以在任何地方访问该对象。

    延迟初始化:单例对象通常在首次访问时才会被创建,实现了延迟初始化的效果。

    限制对象创建:通过私有构造函数,限制其他类直接实例化单例对象。

        单例模式在很多情况下都有用处,例如在需要共享资源、管理全局状态、控制资源访问等场景下可以使用单例模式。然而,过度使用单例模式可能导致代码的可测试性和可维护性下降,因此需要谨慎使用。
    
    • 1

    二、Qt中单例模式的实现

        在Qt中,可以使用以下几种方式来实现单例模式。
    
    • 1

    2.1、静态成员变量

    在类的私有静态成员变量中保存单例对象的指针,并提供一个静态方法来获取该对象。在静态方法中判断对象是否为空,如果为空则创建一个新的对象,否则返回已有的对象。这种方式保证了只有一个实例存在,并且在需要时进行延迟创建。

    class Singleton {
    private:
        static Singleton* instance;
     
        Singleton() {}
     
    public:
        static Singleton* getInstance() {
            if (instance == nullptr) {
                instance = new Singleton();
            }
            return instance;
        }
    };
     
    Singleton* Singleton::instance = nullptr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    使用时,通过静态方法getInstance()获取单例对象:

    Singleton* singleton = Singleton::getInstance();
    
    • 1

    优点:

    • 简单易用,容易理解和实现。
    • 延迟初始化,只在需要时才创建单例对象。
    • 在多线程环境下需要注意线程安全性。
      缺点:
    • 在多线程环境下需要额外处理线程安全性,可能需要使用互斥锁等机制来保护访问。
    • 对象的创建和销毁时机可能不受控制,可能存在资源管理的问题。

    2.2、静态局部变量

    在静态方法中使用静态局部变量保存单例对象的指针。静态局部变量在第一次调用时会被初始化,从而实现了延迟创建的效果。

    class Singleton {
    private:
        Singleton() {}
     
    public:
        static Singleton* getInstance() {
            static Singleton instance;
            return &instance;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    优点:

    • 简洁,没有额外的静态成员变量。
    • 延迟初始化,只在需要时才创建单例对象。
    • 自动处理线程安全性,静态局部变量的初始化具有线程安全性。
      缺点:
    • 在多线程环境下需要注意线程安全性。
    • 对象的创建和销毁时机可能不受控制,可能存在资源管理的问题。

    2.3、Q_GLOBAL_STATIC 宏

    Qt 提供了 Q_GLOBAL_STATIC 宏,可以方便地定义全局的单例对象。这个宏使用了线程安全的延迟初始化机制,并提供了方便的访问方式。

    class Singleton {
    private:
        Singleton() {}
     
    public:
        static Singleton* instance() {
            static Q_GLOBAL_STATIC(Singleton, singleton);
            return singleton;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实例2

    #ifndef CONFIG_H
    #define CONFIG_H
     
    class Config : public QObject {
      Q_OBJECT
     
     public:
      static Config *Instance();
     
      int doSomething()private:
    };
     
    #endif  // CONFIG_H
     
     
    #include "config.h"
     
    Q_GLOBAL_STATIC(Config, config)
     
    Config *Config::Instance() { return config(); }
     
    int Config::doSomething() {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    优点:

    • 简单易用,使用宏定义即可创建全局的单例对象。
    • 延迟初始化,只在需要时才创建单例对象。
    • 自动处理线程安全性,具有线程安全的延迟初始化机制。
      缺点
    • 对象的创建和销毁时机可能不受控制,可能存在资源管理的问题。
    • 不适用于非全局范围的单例对象,只适用于全局单例对象的场景。

    对于 Q_GLOBAL_STATIC 宏,Qt 提供了一种线程安全的延迟初始化机制。这是因为 Q_GLOBAL_STATIC 宏利用了 C++11 中的线程局部存储(thread-local storage)特性来实现。

    线程局部存储是一种在每个线程中独立保存变量的机制,每个线程都有自己的变量实例,互不干扰。Q_GLOBAL_STATIC 宏利用这一特性,将单例对象的实例化和访问限制在每个线程的作用域内。

    具体而言,Q_GLOBAL_STATIC 宏在使用时会根据 C++11 的线程局部存储特性,在每个线程中创建一个静态局部变量。每个线程都有自己的单例对象实例,并且线程之间的访问是互相隔离的,因此不会存在线程安全性问题。

    在第一次访问该单例对象时,Q_GLOBAL_STATIC 宏会使用线程安全的方式进行初始化。在初始化过程中,会通过互斥锁等机制来保护对单例对象的访问,确保只有一个线程可以完成初始化过程。

    通过使用线程局部存储和线程安全的初始化机制,Q_GLOBAL_STATIC 宏实现了线程安全的延迟初始化。这样,即使在多线程环境下同时访问单例对象,也能保证每个线程都能正确地获取到自己的单例对象实例,而不会引发竞争条件或其他线程安全性问题。

    三、使用场景

    单例模式在以下场景中通常被使用:

    1、资源共享:当多个对象需要共享同一个资源时,可以使用单例模式确保只有一个实例存在,从而避免资源的重复创建和管理。

    2、配置管理:单例模式可以用于管理应用程序的配置信息,例如日志配置、数据库连接配置等。通过单例模式,可以在整个应用程序中共享同一份配置数据,方便统一管理和访问。

    3、对象缓存:某些需要频繁创建和销毁的对象,通过单例模式可以将这些对象缓存起来,提高性能和效率。例如线程池、数据库连接池等。

    四、注意事项

    在使用Qt单例模式时,需要注意以下几点:

    1、线程安全性:如果在多线程环境下使用单例模式,需要确保对单例对象的访问是线程安全的。可以采用互斥锁(QMutex)或其他线程同步机制来保护对单例对象的访问。

    2、生命周期管理:单例对象的生命周期通常延续整个应用程序的运行期间。确保在程序退出时,单例对象正确释放资源,避免内存泄漏。

    3、耦合度控制:单例模式会引入全局状态,因此需要谨慎使用,避免过度依赖单例对象,导致代码的耦合度增加。应尽量将单例对象的使用限制在必要的范围内,遵循单一职责原则。

    4、单元测试:单例对象的全局状态可能对代码的单元测试造成一定的影响。在进行单元测试时,需要注意单例对象的影响,并确保测试用例的独立性和可重复性。

    5、可扩展性:在设计单例模式时,需要考虑到未来的扩展需求。如果将来需要创建多个类似的单例对象,需要设计一个可扩展的单例模式框架,以便灵活地管理和创建多个单例对象。

    6、使用合适的方式:Qt提供了多种实现单例模式的方式,如静态成员变量、静态局部变量和Q_GLOBAL_STATIC宏等。根据实际需求选择合适的方式,权衡其优缺点。

    Chapter2 QT单例类管理信号和槽函数

    https://blog.csdn.net/qq_38491692/article/details/124623919

    在QT当中,遇到主界面和多个组件槽函数绑定问题时,为了便于管理,我们可以通过单例类作为第三方来进行管理。

    一、创建单例类

    SignalInstance.h

    #include 
    
    class  SignalInstance:public QObject
    {
    	Q_OBJECT
    public:
    	static SignalInstance	*GetInstance();
    	static void Release();//释放
    	static SignalInstance *signalinstance;
     signals:
    	 void send_to_windwostwo();
    	 void send_to_windwosone();
    private:
    	SignalInstance();
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    SignalInstance.cpp

    #include "SignalInstance.h"
    SignalInstance* SignalInstance::signalinstance = nullptr;//初始化对象
    //释放单例对象
    void SignalInstance::Release()
    {
    	if (signalinstance != NULL)
    	{
    		delete signalinstance;
    		signalinstance = NULL;
    	}
    }
    SignalInstance::SignalInstance()
    {
    	
    }
    //获得单例对象
    SignalInstance* SignalInstance::GetInstance()
    {
    	if (signalinstance == NULL)
    	{
    		signalinstance = new SignalInstance();
    	}
    	return signalinstance;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    二、主界面添加组件

    代码如下(示例):

    #include 
    #include
    #include 
    #include "SignalInstance.h"
    #include"QtWidgets_1.h"
    #include"QtWidgetsClass_2.h"
    #include "instanse.h"
    instanse::instanse(QMainWindow *parent)
        : QMainWindow(parent)
    {
        ui.setupUi(this);
    	QVBoxLayout *lay = new QVBoxLayout(this);
    	QtWidgets_1 *widget1 = new QtWidgets_1();
    	lay->addWidget(widget1);
    	ui.widget->setLayout(lay);
    	QVBoxLayout *lay2 = new QVBoxLayout(this);
    	QtWidgetsClass_2 *widget2 = new QtWidgetsClass_2();
    	lay2->addWidget(widget2);
    	ui.widget_2->setLayout(lay2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    三、组件代码绑定信号和槽

    1.组件1

    #pragma once
    
    #include 
    #include "ui_QtWidgets_1.h"
    
    class QtWidgets_1 : public QWidget
    {
    	Q_OBJECT
    
    public:
    	QtWidgets_1(QWidget *parent = Q_NULLPTR);
    	~QtWidgets_1();
    private slots:
    	void Show();
    private:
    	Ui::QtWidgets_1 ui;
    };
    
    #include "QtWidgets_1.h"
    #include"SignalInstance.h"
    #include 
    #include 
    #pragma execution_character_set("utf-8")
    QtWidgets_1::QtWidgets_1(QWidget *parent)
    	: QWidget(parent)
    {
    	ui.setupUi(this);
    	connect(ui.pushButton, SIGNAL(clicked()), SignalInstance::GetInstance(), SIGNAL(send_to_windwostwo()));//绑定信号
    	connect(SignalInstance::GetInstance(), SIGNAL(send_to_windwosone()), this, SLOT(Show()));//绑定槽函数
    }
    
    QtWidgets_1::~QtWidgets_1()
    {
    
    }
    void QtWidgets_1::Show()
    {
    	ui.textEdit->setText("我是窗口2激活的");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2.组件2

    #pragma once
    
    #include 
    #include "ui_QtWidgetsClass_2.h"
    
    class QtWidgetsClass_2 : public QWidget
    {
    	Q_OBJECT
    
    public:
    	QtWidgetsClass_2(QWidget *parent = Q_NULLPTR);
    	~QtWidgetsClass_2();
    private slots:
    	void Show();
    private:
    	Ui::QtWidgetsClass_2 ui;
    };
    
    
    #include "QtWidgetsClass_2.h"
    #include"SignalInstance.h"
    #include 
    #include 
    #pragma execution_character_set("utf-8")
    QtWidgetsClass_2::QtWidgetsClass_2(QWidget *parent)
    	: QWidget(parent)
    {
    	ui.setupUi(this);
    	connect(SignalInstance::GetInstance(), SIGNAL(send_to_windwostwo()),this,SLOT(Show()));//绑定槽函数
    	connect(ui.pushButton, SIGNAL(clicked()), SignalInstance::GetInstance(), SIGNAL(send_to_windwosone()));//绑定信号
    }
    
    QtWidgetsClass_2::~QtWidgetsClass_2()
    {
    }
    void QtWidgetsClass_2::Show()
    {
    	ui.textEdit->setText("我是窗口1激活的");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    四、效果图

    在这里插入图片描述

    总结

    本文案例使用组件较少,当项目较大时,比如上千个控件和布局,能有效的对信号和槽进行管理。

    Chapter3 Qt单例模式的消息全局响应类($$$)

    原文链接:https://blog.csdn.net/sunnyloves/article/details/125234467

    由来

    在飞扬青云大佬的文章Qt开发经验里的第82条写道:

    Qt的信号槽机制非常牛逼,也是Qt的独特的核心功能之一,有时候我们在很多窗体中传递信号来实现更新或者处理,如果窗体层级比较多,比如窗体A的父类是窗体B,窗体B的父类是窗体C,窗体C有个子窗体D,如果窗体A一个信号要传递给窗体D,问题来了,必须先经过窗体B中转到窗体C再到窗体D才行,这样的话各种信号关联信号的connect会非常多而且管理起来比较乱,可以考虑增加一个全局的单例类AppEvent,公共的信号放这里,然后窗体A对应信号绑定到AppEvent,窗体D绑定AppEvent的信号到对应的槽函数即可,干净清爽整洁。

    代码

    于是想办法写了一个类GlobalMessageHelper 注意这个类用的是单例的设计模式。
    验证的思路是写了4个窗口ABCD,其中A点击按钮弹窗D,B点击按钮弹窗C,C里点击按钮将其中LineEdit输入的内容传递到D里去。如果普通的传递路线应该是C->B->main->A->D(当然可以直接C->D,但是如果项目里很多这种跨窗口的消息直接传递,就会形成飞扬大佬提到的复杂情况)。用GlobalMessageHelper 类后,就可以通过它实现所有sender和receiver直接连接。效果可以看下一节。

    GlobalMessageHelper.h文件

    // GlobalMessageHelper  h文件
    #include 
    #include 
    class GlobalMessageHelper : public QObject
    {
      Q_OBJECT
    public:
    
      ~GlobalMessageHelper();
    
      static GlobalMessageHelper *getInstance();
    
    signals:
      void sendToAFromB(const QString &str);
      void sendToCFromD(const QString &str);
    private:
      GlobalMessageHelper(QObject *parent = nullptr);
      static GlobalMessageHelper *gMessageHelper;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    globalmessagehelper.cpp文件

    // cpp文件
    #include "globalmessagehelper.h"
    GlobalMessageHelper *GlobalMessageHelper::gMessageHelper;
    
    GlobalMessageHelper::GlobalMessageHelper(QObject *parent) :
      QObject{parent}
    {
    }
    
    GlobalMessageHelper::~GlobalMessageHelper()
    {
    }
    
    GlobalMessageHelper *GlobalMessageHelper::getInstance()
    {
      if (!GlobalMessageHelper::gMessageHelper)
        GlobalMessageHelper::gMessageHelper = new GlobalMessageHelper;
    
      return GlobalMessageHelper::gMessageHelper;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    DialogA.h/cpp文件

    // DialogA  h文件
    #include 
    #include 
    #include 
    class DialogA : public QDialog
    {
      Q_OBJECT
    public:
      DialogA(QDialog *parent = nullptr);
    };
    
    
    // DialogA  cpp文件
    #include "dialoga.h"
    #include "dialogd.h"
    #include "globalmessagehelper.h"
    #include 
    #include 
    #include 
    #include 
    DialogA::DialogA(QDialog *parent) : QDialog(parent)
    {
      setWindowTitle("DialogA");
      setMinimumSize(QSize(300, 100));
      QVBoxLayout *lay = new QVBoxLayout;
      setLayout(lay);
      QPushButton *btn = new QPushButton("BTN");
      lay->addWidget(btn);
      connect(btn, &QPushButton::clicked, this,
              [&]()
      {
        DialogD *dlg = new DialogD;
        dlg->show();
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    DialogB.h/cpp文件

    // DialogB  h文件
    #include 
    #include 
    
    class DialogB : public QDialog
    {
      Q_OBJECT
    public:
      DialogB(QDialog *parent = nullptr);
    };
    
    
    // DialogB  cpp文件
    #include "dialogb.h"
    #include "dialogc.h"
    #include 
    #include 
    DialogB::DialogB(QDialog *parent) : QDialog(parent)
    {
      setWindowTitle("DialogB");
      setMinimumSize(QSize(300, 100));
      QVBoxLayout *lay = new QVBoxLayout;
      setLayout(lay);
      QPushButton *btn = new QPushButton("BTN");
      lay->addWidget(btn);
      connect(btn, &QPushButton::clicked, this,
              [&]()
      {
        DialogC *dlg = new DialogC;
        dlg->show();
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    DialogC.h/cpp文件

    // DialogC  h文件
    #include 
    #include 
    #include 
    class DialogC : public QDialog
    {
      Q_OBJECT
    public:
      DialogC(QDialog *parent = nullptr);
    
    private:
      QLineEdit *line = nullptr;
      QPushButton *btn = nullptr;
    };
    
    
    // DialogC  cpp文件
    #include "dialogc.h"
    #include "globalmessagehelper.h"
    #include 
    #include 
    #include 
    DialogC::DialogC(QDialog *parent) : QDialog(parent)
    {
      setWindowTitle("DialogC");
      setMinimumSize(QSize(300, 100));
      QVBoxLayout *lay = new QVBoxLayout;
      setLayout(lay);
    
      line = new QLineEdit;
      lay->addWidget(line);
      btn = new QPushButton("Send");
      lay->addWidget(btn);
      connect(btn, &QPushButton::clicked, this,
              [&]()
      {
        emit GlobalMessageHelper::getInstance()->sendToAFromB(line->text());
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    DialogD.h/cpp文件

    // DialogD  h文件
    #include 
    #include 
    class QLineEdit;
    class DialogD : public QDialog
    {
    public:
      DialogD();
      QLineEdit *line = nullptr;
    };
    
    
    // DialogD  cpp文件
    #include "dialogd.h"
    #include "globalmessagehelper.h"
    #include 
    #include 
    DialogD::DialogD()
    {
      setWindowTitle("DialogD");
      setMinimumSize(QSize(300, 100));
      QVBoxLayout *lay = new QVBoxLayout;
      setLayout(lay);
      line = new QLineEdit;
      lay->addWidget(line);
      connect(GlobalMessageHelper::getInstance(), &GlobalMessageHelper::sendToAFromB, this,
              [&](const QString &s)
      {
        Q_ASSERT(GlobalMessageHelper::getInstance() != nullptr);
    
        line->setText(s);
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    main.cpp 文件

    // main.cpp  文件
    
    #include "globalmessagehelper.h"
    #include "dialoga.h"
    #include "dialogc.h"
    #include "dialogb.h"
    
    #include 
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
    
      DialogA dlgA;
      DialogB dlgB;
      dlgA.show();
      dlgB.show();
      return a.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行结果

    在这里插入图片描述

    Chapter4 Qt全局信号通信

    原文链接:https://blog.csdn.net/u012790503/article/details/81950467

    应用场景分析

    Qt开发中经常会遇到作用域跨度比较大的对象间通信的场景,如果直接使用信号槽通过对象指针直接连接,首先需要将对象指针互相暴露出来,其中可能涉及到各种复杂的传递过程,导致程序混乱。一种解决方案是建立全局的信号中转站,实现全局范围内的便捷通信。

    功能实现1

    设现有对象A,需要将信号signalA()发送给对象B。

    建立单例类class SIgnalStation。
    在单例类中定义中转信号void transSignalA()。
    在A的代码中,将A的信号与信号中转的信号连接:
    A:: connect(this, SIGNAL(signalA()), SIgnalStation::instance(), SIGNAL(transSignalA()));
    在对象B中连接中转信号:
    B::connect(SignalStation::instance(), SIGNAL(transSignalA()), this, SLOT(…));
    这样就实现了进程中任何对象间信号传递。

    功能实现2

    此种实现是用ID或字符串来实现对信号的索引,如下表所示:
    在这里插入图片描述

    通过这样的映射,可以实现更低的耦合,映射由一个管理器管理,如GlobalMsgMgr类。此类提供两个接口:

    addEmit(const char *msg_id(信号ID), const char *signal(信号签名)):用于将本地信号绑定到信号ID上,本地信号触发时,自动触发所有连接到此信号ID上的槽。
    addSlot(const char *msg_id(信号ID), const char *slot(槽签名)):用于将本地槽绑定到信号ID上,任意信号触发源触发此信号时,本地槽会被调用。

    综上,
    实现2比实现1的耦合程度更低,单从ID上看不出信号参数类型;好处是可以通过ID实现更松的耦合,甚至可以实现信号ID的比较运算。
    实现1、实现2在触发信号时稍微麻烦一点,因为触发信号时,需要定义本地的信号。

    功能实现3

    参考:Qt使用信号槽模拟全局广播
    这种方式在发送信号时较为简单,但是在定义和编译时略复杂。

    个人建议,在简单应用下,使用功能实现1;在复杂应用下,使用功能实现2。

    FAQ

    为什么不用回调函数呢,因为信号槽可以很容易实现跨线程通信,回调函数跨线程调用需要处理竞争同步的问题。

    总结

     emit AppEvent::getHandle()->sigSendToMainWindow("从User发出的AppEvent信号到主程序");
    
    • 1

    mainwindow.cpp中

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        connect(AppEvent::getHandle(), SIGNAL(sigSendToMainWindow(QString)), this, SLOT(slotUser(QString)));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    void MainWindow::slotUser(QString str)
    {
    qDebug()<<__FUNCTION__<<tr("MainWindow::slotUser(QString str)被调用:")<<str;
    }
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    C Primer Plus(6) 中文版 第3章 数据和C 3.1 示例程序
    sop流程图怎么做?sop流程图可以用什么做好?
    [附源码]Python计算机毕业设计Django人事系统
    Git拉取远程仓库代码与本地分支代码相关流程
    一、认识OSS
    web二级操作题
    UE4 C++设计模式:策略模式(Strategy Pattern)
    【OpenCV】—输入输出XML和YAML文件
    通过docker部署grafana和mysql
    程序员的护城河是什么?开源和免费就是卷死自己和同行
  • 原文地址:https://blog.csdn.net/m0_46577050/article/details/134047342