当前位置: 首页 > news >正文

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
    • 功能实现3
    • FAQ


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.h"Q_GLOBAL_STATIC(Config, config)Config *Config::Instance() { return config(); }int Config::doSomething() {
}

优点:

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

对于 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 <QObject>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();
};

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>
#include<QVBoxLayout>
#include <QtWidgets/QWidget>
#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.组件1

#pragma once#include <QWidget>
#include "ui_QtWidgets_1.h"class 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"
#include"SignalInstance.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.h"class 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"
#include"SignalInstance.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点击按钮弹窗D,B点击按钮弹窗C,C里点击按钮将其中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 <QWidget>class 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 <QApplication>int 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

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

相关文章:

Qt中的单例模式

QT单例类管理信号和槽函数 Chapter1 Qt中的单例模式一、什么是单例模式&#xff1f;二、Qt中单例模式的实现2.1、静态成员变量2.2、静态局部变量2.3、Q_GLOBAL_STATIC 宏实例2 三、使用场景四、注意事项 Chapter2 QT单例类管理信号和槽函数一、创建单例类二、主界面添加组件三、…...

ROS自学笔记十五:URDF工具

要使用工具之前&#xff0c;首先需要安装&#xff0c;安装命令: sudo apt install liburdfdom-tools 1.check_urdf 语法检查 在ROS中&#xff0c;你可以使用.check_urdf命令行工具来对URDF&#xff08;Unified Robot Description Format&#xff09;文件进行语法检查和验证。…...

Pytorch代码入门学习之分类任务(三):定义损失函数与优化器

一、定义损失函数 1.1 代码 criterion nn.CrossEntropyLoss() 1.2 损失函数简介 神经网络的学习通过某个指标表示目前的状态&#xff0c;然后以这个指标为基准&#xff0c;寻找最优的权重参数。神经网络以某个指标为线索寻找最优权重参数&#xff0c;该指标称为损失函数&am…...

【Linux】安装VMWare虚拟机(安装配置)和配置Windows Server 2012 R2(安装配置连接vm虚拟机)以及环境配置

前言&#xff1a; 一、操作系统简介 1、什么是操作系统 操作系统是一种软件&#xff0c;它管理计算机系统的硬件和软件资源&#xff0c;并提供给用户和应用程序接口&#xff0c;使它们能够与计算机系统交互和运行。操作系统负责调度和分配系统资源&#xff0c;例如处理器、内存…...

Python入口顶部人体检测统计进出人数

程序示例精选 Python入口顶部人体检测统计进出人数 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Python入口顶部人体检测统计进出人数》编写代码&#xff0c;代码整洁&#xff0c;规则&a…...

移动端自动化-Appium元素定位

文章目录 Appium元素定位第一类&#xff1a;属性定位第二类&#xff1a;路径定位 常见问题理解appium server 和 appium inspector 以及 appium-python-client的关系 appium是跨平台的&#xff0c;支持OSX&#xff0c;Windows以及Linux系统。它允许测试人员在不同的平台&#x…...

menuconfig 图形化配置原理说明三

一. 简介 本文继续简单了解一下&#xff0c;uboot的图形化配置原理。具体了解 Kconfig语法。 之前文章了解了几个 Kconfig语法。地址如下&#xff1a; menuconfig 图形化配置原理说明二-CSDN博客 二. menuconfig 图形化配置之 Kconfig语法 1. config 条目 顶层 Kconfig …...

Ansible简介

环境 控制节点&#xff1a;Ubuntu 22.04Ansible 2.10.8管理节点&#xff1a;CentOS 8 组成 Ansible环境主要由三部分组成&#xff1a; 控制节点&#xff08;Control node&#xff09;&#xff1a;安装Ansible的节点&#xff0c;在此节点上运行Ansible命令管理节点&#xff…...

Tomcat+nginx负载均衡和动静分离

Nginx实现负载均衡和动静分离的原理 Nginx实现负载均衡是通过反向代理实现Nginx服务器作为前端&#xff0c;Tomcat服务器作为后端&#xff0c;web页面请求由Nginx服务来进行转发。 但是不是把所有的web请求转发&#xff0c;而是将静态页面请求Ncinx服务器自己来处理&#xff0c…...

全景环视AVM标定

目录 一、前言 二、鱼眼模型 三、标定流程 四、角点提取 4.1 亚像素坐标计算...

【JavaScript】leetcode链表相关题解

【JavaScript】leetcode链表相关题解 一、什么是链表&#xff1f;二、Javascript中的链表三、leetcode相关链表2.两数相加237.删除链表中的节点206.反转链表 &#x1f48e;个人主页: 阿选不出来 &#x1f48e;个人简介: 大三学生&#xff0c;热爱Web前端&#xff0c;随机掉落学…...

洞察运营机会的数据分析利器

这套分析方法包括5个分析工具&#xff1a; 用“描述性统计”来快速了解数据的整体特点。用“变化分析”来寻找数据的问题和突破口。用“指标体系”来深度洞察变化背后的原因。用“相关性分析”来精确判断原因的影响程度。用“趋势预测”来科学预测未来数据的走势&#xff0c;...

使用Python实现文字的声音播放

winsound 是 Python 的一个内置模块&#xff0c;它提供了访问 Windows 操作系统的声音播放功能的接口。这个模块可以用来播放简单的声音&#xff0c;例如提示音或者短促的音效。 # Author : 小红牛 # 微信公众号&#xff1a;WdPython import win32com.client import winsound#…...

gulp自动化构建

什么是Gulp? Gulp是一种前端开发过程中广泛使用的自动化构建工具&#xff0c;它是基于Node.js构建的&#xff0c;能够极大地提高开发效率和代码质量。Gulp的主要功能包括文件的压缩、合并、重命名等&#xff0c;同时它也支持文件监听和浏览器自动刷新等功能。使用Gulp&#x…...

java时间解析生成定时Cron表达式工具类

Cron表达式工具类CronUtil 构建Cron表达式 /****方法摘要&#xff1a;构建Cron表达式*param taskScheduleModel*return String*/public static String createCronExpression(TaskScheduleModel taskScheduleModel){StringBuffer cronExp new StringBuffer("");if(…...

JavaEE 网络原理——TCP的工作机制(末篇 其余TCP特点)

文章目录 一、滑动窗口二、流量控制三、拥堵控制四、延时应答五、捎带应答六、面向字节流七、异常情况八、总结 其余相关文章&#xff1a; JavaEE 网络原理——TCP的工作机制(中篇 三次握手和四次挥手) 本篇文章衔接的是前面两篇文章的内容&#xff0c;在这里继续解释 TCP 的内…...

【软件测试】了解JUnit单元测试框架常用注解

目录 1、认识JUnit 2、Junit中常见的注解 1、Test 2、Disabled 3、BeforeAll和AfterAll 4、BeforeEach和AfterEach 5、 ParameterizedTest&#xff1a;参数化 6、order 3、断言 1、断言相等【Assertions.assertEquals(预期&#xff0c;比较值)】&#xff1b;相等测试通…...

【广州华锐互动】三维全景3D消防科普展馆

在我们的日常生活中&#xff0c;火灾安全是一个不容忽视的重要问题。然而&#xff0c;由于缺乏对火灾的了解和应对技巧&#xff0c;许多人在面对火灾时往往感到无助和恐慌。为了解决这个问题&#xff0c;广州华锐互动开发了三维全景3D消防科普展馆&#xff0c;它是一个以虚拟现…...

某大型车企:加强汽车应用安全防护,开创智能网联汽车新篇章

​某车企是安徽省最大的整车制造企业&#xff0c;致力于为全球消费者带来高品质汽车产品和服务体验&#xff0c;是国内最早突破百万销量的汽车自主品牌。该车企利用数字技术推动供应链网络的新型互动&#xff0c;加快数字化转型&#xff0c;持续进行场景创新、生态创新&#xf…...

LLVM学习笔记(50)

4.1.4. DAG合并与合法化 来自SelectionDAGBuilder的SelectionDAG输出还不能进行指令选择&#xff0c;必须通过额外的转换——显示在上图。在指令选择前应用的遍序列如下&#xff1a; 匹配一组节点&#xff0c;在有利时使用更简单的构造来替换它们&#xff0c;DAG合并遍优化Se…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...