wordpress国内网站,西安做网站哪里价格低,新手怎么做美工图,建筑网站首页QT单例类管理信号和槽函数 Chapter1 Qt中的单例模式一、什么是单例模式#xff1f;二、Qt中单例模式的实现2.1、静态成员变量2.2、静态局部变量2.3、Q_GLOBAL_STATIC 宏实例2 三、使用场景四、注意事项 Chapter2 QT单例类管理信号和槽函数一、创建单例类二、主界面添加组件三、… QT单例类管理信号和槽函数 Chapter1 Qt中的单例模式一、什么是单例模式二、Qt中单例模式的实现2.1、静态成员变量2.2、静态局部变量2.3、Q_GLOBAL_STATIC 宏实例2 三、使用场景四、注意事项 Chapter2 QT单例类管理信号和槽函数一、创建单例类二、主界面添加组件三、组件代码绑定信号和槽四、效果图总结 Chapter3 Qt单例模式的消息全局响应类($$$)由来代码GlobalMessageHelper.h文件globalmessagehelper.cpp文件DialogA.h/cpp文件DialogB.h/cpp文件DialogC.h/cpp文件DialogD.h/cpp文件main.cpp 文件 运行结果 Chapter4 Qt全局信号通信应用场景分析功能实现1功能实现2功能实现3FAQ Chapter1 Qt中的单例模式
原文链接https://blog.csdn.net/baidu_18624493/article/details/130573407
一、什么是单例模式 单例模式是一种创建型设计模式用于确保类只有一个实例存在并提供全局访问点以便于其他对象获取该实例。在单例模式中类只能实例化一次并提供了一个静态方法或全局访问点来获取该实例。这样可以确保在整个应用程序中只有一个实例存在并且可以通过该实例进行操作和访问。单例模式的特点包括
单一实例单例模式确保类只有一个实例存在。
全局访问点通过静态方法或全局访问点获取单例对象可以在任何地方访问该对象。
延迟初始化单例对象通常在首次访问时才会被创建实现了延迟初始化的效果。
限制对象创建通过私有构造函数限制其他类直接实例化单例对象。 单例模式在很多情况下都有用处例如在需要共享资源、管理全局状态、控制资源访问等场景下可以使用单例模式。然而过度使用单例模式可能导致代码的可测试性和可维护性下降因此需要谨慎使用。二、Qt中单例模式的实现 在Qt中可以使用以下几种方式来实现单例模式。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;使用时通过静态方法getInstance()获取单例对象
Singleton* singleton Singleton::getInstance();优点
简单易用容易理解和实现。延迟初始化只在需要时才创建单例对象。在多线程环境下需要注意线程安全性。 缺点在多线程环境下需要额外处理线程安全性可能需要使用互斥锁等机制来保护访问。对象的创建和销毁时机可能不受控制可能存在资源管理的问题。
2.2、静态局部变量
在静态方法中使用静态局部变量保存单例对象的指针。静态局部变量在第一次调用时会被初始化从而实现了延迟创建的效果。
class Singleton {
private:Singleton() {}public:static Singleton* getInstance() {static Singleton instance;return instance;}
};优点
简洁没有额外的静态成员变量。延迟初始化只在需要时才创建单例对象。自动处理线程安全性静态局部变量的初始化具有线程安全性。 缺点在多线程环境下需要注意线程安全性。对象的创建和销毁时机可能不受控制可能存在资源管理的问题。
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;}
};实例2
#ifndef CONFIG_H
#define CONFIG_Hclass Config : public QObject {Q_OBJECTpublic:static Config *Instance();int doSomething()private:
};#endif // CONFIG_H#include config.hQ_GLOBAL_STATIC(Config, config)Config *Config::Instance() { return config(); }int Config::doSomething() {
}优点
简单易用使用宏定义即可创建全局的单例对象。延迟初始化只在需要时才创建单例对象。自动处理线程安全性具有线程安全的延迟初始化机制。 缺点对象的创建和销毁时机可能不受控制可能存在资源管理的问题。不适用于非全局范围的单例对象只适用于全局单例对象的场景。
对于 Q_GLOBAL_STATIC 宏Qt 提供了一种线程安全的延迟初始化机制。这是因为 Q_GLOBAL_STATIC 宏利用了 C11 中的线程局部存储thread-local storage特性来实现。
线程局部存储是一种在每个线程中独立保存变量的机制每个线程都有自己的变量实例互不干扰。Q_GLOBAL_STATIC 宏利用这一特性将单例对象的实例化和访问限制在每个线程的作用域内。
具体而言Q_GLOBAL_STATIC 宏在使用时会根据 C11 的线程局部存储特性在每个线程中创建一个静态局部变量。每个线程都有自己的单例对象实例并且线程之间的访问是互相隔离的因此不会存在线程安全性问题。
在第一次访问该单例对象时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 QObjectclass 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();
};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;
}二、主界面添加组件
代码如下示例
#include QObject
#includeQVBoxLayout
#include QtWidgets/QWidget
#include SignalInstance.h
#includeQtWidgets_1.h
#includeQtWidgetsClass_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.组件1
#pragma once#include QWidget
#include ui_QtWidgets_1.hclass QtWidgets_1 : public QWidget
{Q_OBJECTpublic:QtWidgets_1(QWidget *parent Q_NULLPTR);~QtWidgets_1();
private slots:void Show();
private:Ui::QtWidgets_1 ui;
};#include QtWidgets_1.h
#includeSignalInstance.h
#include QObject
#include QtWidgets/QWidget
#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激活的);
}2.组件2
#pragma once#include QWidget
#include ui_QtWidgetsClass_2.hclass QtWidgetsClass_2 : public QWidget
{Q_OBJECTpublic:QtWidgetsClass_2(QWidget *parent Q_NULLPTR);~QtWidgetsClass_2();
private slots:void Show();
private:Ui::QtWidgetsClass_2 ui;
};#include QtWidgetsClass_2.h
#includeSignalInstance.h
#include QObject
#include QtWidgets/QWidget
#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激活的);
}四、效果图 总结
本文案例使用组件较少当项目较大时比如上千个控件和布局能有效的对信号和槽进行管理。
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点击按钮弹窗DB点击按钮弹窗CC里点击按钮将其中LineEdit输入的内容传递到D里去。如果普通的传递路线应该是C-B-main-A-D当然可以直接C-D,但是如果项目里很多这种跨窗口的消息直接传递,就会形成飞扬大佬提到的复杂情况)。用GlobalMessageHelper 类后就可以通过它实现所有sender和receiver直接连接。效果可以看下一节。
GlobalMessageHelper.h文件
// GlobalMessageHelper h文件
#include QWidget
#include QObject
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;
};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;
}DialogA.h/cpp文件
// DialogA h文件
#include QDialog
#include QWidget
#include QLineEdit
class DialogA : public QDialog
{Q_OBJECT
public:DialogA(QDialog *parent nullptr);
};// DialogA cpp文件
#include dialoga.h
#include dialogd.h
#include globalmessagehelper.h
#include QVBoxLayout
#include QPushButton
#include QLineEdit
#include QDebug
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();});
}DialogB.h/cpp文件
// DialogB h文件
#include QDialog
#include QWidgetclass DialogB : public QDialog
{Q_OBJECT
public:DialogB(QDialog *parent nullptr);
};// DialogB cpp文件
#include dialogb.h
#include dialogc.h
#include QVBoxLayout
#include QPushButton
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();});
}DialogC.h/cpp文件
// DialogC h文件
#include QDialog
#include QWidget
#include QLineEdit
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 QVBoxLayout
#include QPushButton
#include QDebug
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());});
}DialogD.h/cpp文件
// DialogD h文件
#include QDialog
#include QWidget
class QLineEdit;
class DialogD : public QDialog
{
public:DialogD();QLineEdit *line nullptr;
};// DialogD cpp文件
#include dialogd.h
#include globalmessagehelper.h
#include QLineEdit
#include QVBoxLayout
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);});
}main.cpp 文件
// main.cpp 文件#include globalmessagehelper.h
#include dialoga.h
#include dialogc.h
#include dialogb.h#include QApplicationint main(int argc, char *argv[])
{QApplication a(argc, argv);DialogA dlgA;DialogB dlgB;dlgA.show();dlgB.show();return a.exec();
}运行结果 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
为什么不用回调函数呢因为信号槽可以很容易实现跨线程通信回调函数跨线程调用需要处理竞争同步的问题。