如何在退出Qt时保存用户配置

如何在退出Qt时保存用户配置

文章目录

  • 如何在退出Qt时保存用户配置
    • 一、简介
    • 二、 保存配置数据(方法一)
      • 2.1 项目实现
      • 2.2 运行结果
    • 三、保存配置数据(方法二)
      • 3.1 项目实现
      • 3.2 运行结果
    • 四、写在最后

一、简介

在我们使用 Qt 进行编写软件的时候,相必都会有一个疑惑,就是怎么在退出的时候对用户配置信息进行保存,这样下次在打开软件的时候,不需要重新配置,大大提升用户体验。

这个想法起源于 正点原子 XCOM 软件,这里我粘贴出链接:

【正点原子】XCOM串口调试助手软件V2.6版本发布,使用方便广泛的串口调试助手-OpenEdv-开源电子网

如点击无法进行跳转,可以自行复制以下链接进行手动跳转:

  • http://www.openedv.com/thread-279749-1-1.html

这里对该软件进行简单介绍,其是一个用于显示 串口信息 的上位机工具,在使用过程中,当我们配置好波特率等信息以后,退出再次启用的时候,仍然会恢复成我们退出之前的配置信息。其界面如下所示:

在这里插入图片描述

那么基于这样的设定,我们不止可以用在上位机中,也可以用在其他 需要保存用户配置数据的场景中。因此,我写了这篇文章,用于介绍 如何在Qt退出时保存用户配置数据

通过本文,你将学会以下内容:

  1. 学会在 Qt 程序退出时,保存用户配置数据信息。
  2. 在打包情况下,如何更好的保存数据

那么在开始之前,这里我先介绍以下我所使用的开发环境:

  • Windows 10 x64
  • Qt 5.12.3 (MinGw 32bit)

二、 保存配置数据(方法一)

在此方法中,我们将采取 ini 文件的形式对用户配置信息进行保存,这种形式的好处在于直观,且用户可修改。

在开始之前,我这对采取的 UI 进行简单描述,如下所示:

在这里插入图片描述

在两种方法中,将均采用此 UI 进行开发演示!!!

可以从图中看到,我仿照 正点原子 XCOM 对串口配置部分进行绘制显示。因此,我们需要 在退出的时候保存五个下拉复选框中的配置信息

值得注意的是,对波特率下拉复选框的处理中,我并没有直接在 UI 中添加数据,而是通过代码函数进行添加的,而停止位、数据位、校验位均在 UI 中完成添加。

其实效果都一样,本文重点不在此处,只是给大家提供一种新的思路。

那么,我这里建立项目结构如下所示:

在这里插入图片描述

在前面的讲解中,已经对 quitsave.ui 进行了配置,接下来将书写实现代码。

2.1 项目实现

  1. quitsave.h 中书写如下所示代码:

    #ifndef QUITSAVE_H
    #define QUITSAVE_H#include <QWidget>#include <QSettings>#include <QtSerialPort/QSerialPort>
    #include <QtSerialPort/QSerialPortInfo>namespace Ui {
    class QuitSave;
    }class QuitSave : public QWidget
    {Q_OBJECTpublic:explicit QuitSave(QWidget *parent = nullptr);~QuitSave();private:Ui::QuitSave *ui;// 串口对象QSerialPort* mySerialPort;// QSettings 对象QSettings*   mySettings;/* ui 初始化 */void ui_Init(void);void loadConfig(void);/* 保存配置 */void saveConfig(void);
    };#endif // QUITSAVE_H
  2. quitsave.cpp 中进行如下实现:

    #include "quitsave.h"
    #include "ui_quitsave.h"#include <QDebug>QuitSave::QuitSave(QWidget *parent) :QWidget(parent),ui(new Ui::QuitSave)
    {ui->setupUi(this);mySerialPort = new QSerialPort;mySettings = new QSettings("config.ini", QSettings::IniFormat);// ui 初始化ui_Init();// 根据配置设置 UIloadConfig();
    }QuitSave::~QuitSave()
    {// 保存配置项saveConfig();delete mySettings;delete mySerialPort;delete ui;
    }/*!*  @File        : quitsave.cpp*  @Brief       : UI 初始化函数*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 10:35:52*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::ui_Init()
    {// 获取串口端口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ui->comboBox->addItem(info.portName() + ":"+ info.description(), info.portName());  // 将端口号以及设备描述信息写入UI}// 添加典型波特率foreach (auto baudRate, QSerialPortInfo::standardBaudRates()) {ui->baundComboBox->addItem(QString::number(baudRate, 10), QString::number(baudRate, 10));}}/*!*  @File        : quitsave.cpp*  @Brief       : 加载配置信息*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 13:11:45*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::loadConfig()
    {QString comx = mySettings->value("/com/comx").toString();           // 获取 COM 接口QString baund = mySettings->value("/com/baund").toString();         // 获取 baund 接口QString stop = mySettings->value("/com/stop").toString();           // 获取 stop 接口QString data = mySettings->value("/com/data").toString();           // 获取 data 接口QString check = mySettings->value("/com/check").toString();         // 获取 check 接口/* 获取设备列表 */int count = ui->comboBox->count();                                  // 获取所有元素int index = 0;for(index = 0; index < count; index++) {if (ui->comboBox->itemData(index).toString() == comx)break;}/* 刷新 UI */ui->comboBox->setCurrentIndex(index == count ? 0 : index);ui->baundComboBox->setCurrentText(baund);ui->stopComboBox->setCurrentText(stop);ui->dataComboBoBox->setCurrentText(data);ui->checkComboBox->setCurrentText(check);
    }/*!*  @File        : quitsave.cpp*  @Brief       : 保存配置文件*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 11:20:02*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::saveConfig()
    {// 将读取的内容进行保存mySettings->setValue("/com/comx", ui->comboBox->currentData());                         // 保存端口号mySettings->setValue("/com/baund", ui->baundComboBox->currentText());                   // 保存波特率mySettings->setValue("/com/stop", ui->stopComboBox->currentText());                     // 保存停止位mySettings->setValue("/com/data", ui->dataComboBoBox->currentText());                   // 保存数据位mySettings->setValue("/com/check", ui->checkComboBox->currentText());                   // 保存校验位
    }

对于上述代码中,构造部分有以下代码:

mySerialPort = new QSerialPort;mySettings = new QSettings("config.ini", QSettings::IniFormat);// ui 初始化
ui_Init();// 根据配置设置 UI
loadConfig();

其中,创建了 QSerialPort 对象和 QSettings 对象,我们实现用户配置信息的保存也是基于 QSettings 进行的。

值得注意的是,我们通过 QSettings 创建了一个 config.ini 文件,用于保存配置信息。如果该文件,则直接可以进行读取和写入,否则将会新创建文件。

随后对 UI 进行初始化,这部分代码主要是实现 串口设备检测和串口典型波特率写入。具体实现内容可以在上述代码中找到。

最后对 UI 进行设置,加载关闭之前的用户配置信息。在该函数中,也是通过读取 ini 文件完成对 UI 的操作。

而在析构部分,通过调用 saveConfig() 函数实现了关键信息的保存。其函数内部也是通过写入 ini 文件得以实现的。

那么,说了很多,ini 文件中到底有什么呢?接下来我将解答大家的疑惑,其中 config.ini 文件的内容如下所示:

[com]
comx=COM58
baund=115200
stop=1
data=8
check=None

ini 文件是 initialization file 的缩写,即 初始化文件,是 widows 系统配置文件所采用的存储格式。而对于以上内容,例如 comx=COM58 叫做参数,其存在的结构我们称之为 键值对,即 comx 为键,COM58 为值。相信学过 JSON、C++ 的朋友都很熟悉,这里我们也可以 简单理解为一个变量对应一个具体的值。而 [com] 叫做 ,它将所有的键值对结合在一起。在我们的例子中,comx、baund、stop、data、check 都属 com 这个节中的参数。

有关 ini 文件的具体信息,大家可以参考以下文章:

ini配置文件_ini文件-CSDN博客

如点击无法进行跳转,可以自行复制以下链接进行手动跳转:

  • https://blog.csdn.net/first_bug/article/details/129693732

这里提醒大家一下,该文件默认存放在编译输出文件中!!!例如,我采用的是 MinGW 32bit Debug 进行编译,则其文件位于:

在这里插入图片描述

大家想放在其他位置,也可以自行通过 QSettings 构造函数进行实现。

因此,在我们写入 ini 文件的时候采用如下所示的形式:

mySettings->setValue("/com/comx", ui->comboBox->currentData());

其中我们通过 com 节,访问到其中的 comx 键,对 comx 键进行赋值。所以其路径也就是 /com/comx

同样的在我们读取的时候也是通过这样的形式进行实现,如下所示:

mySettings->value("/com/comx")

需要知道的是,无论是写入还是读取,其传入、传出的参数类型均为 QVariant,该类型能够存储和传递各种类型的数据,对于没有的数据类型,也可以自己进行定义。因此,在我们实际使用的过程中,一般进行以下形式的实现:

QString comx = mySettings->value("/com/comx").toString();  

通过使用 toString() 方法将存储的数据转成 QString 类型。

有关 QVariant 的相关内容,大家可以参考如下所示的文章:

QVariant的用法-CSDN博客

如点击无法进行跳转,可以自行复制以下链接进行手动跳转:

  • https://blog.csdn.net/xiaopei_yan/article/details/81410092

通过这种实现形式,我们使用 Qt 打包工具进行简单打包,得到以下文件结构:

在这里插入图片描述

注意需要将 config.ini 文件放到 quitSave.exe 文件的同一目录中。

但这种方法也有缺点,其可以被用户进行随意修改,而且不利于存储敏感数据。有的朋友还会选择使用 Enigma Virtual Box 进行二次打包成单独的 .exe 文件。我这里尝试过,进行二次打包之后,ini 文件的作用将失效,即无法保存用户配置信息。但这种做法存在着一定的好处,那就是更为直观,在我们调试过程中也更加方便。

2.2 运行结果

使用 Qt 进行打包之后运行效果如下所示:

在这里插入图片描述

可以看到,在初次对 串口设备 以及 波特率 进行设置之后,再次启动软件,其已经设置为我们退出之前的状态。


三、保存配置数据(方法二)

另一种方法仍然采用 QSettings 类进行操作,不同的是,我们不再使用 ini 文件进行存储。

这里 ui 设计与 方法一 中相同,文件结构也相同,这里我就不再赘述了,直接开始书写代码。

3.1 项目实现

  1. quitsave.h 中书写如下所示代码:

    #ifndef QUITSAVE_H
    #define QUITSAVE_H#include <QWidget>#include <QSettings>#include <QtSerialPort/QSerialPort>
    #include <QtSerialPort/QSerialPortInfo>namespace Ui {
    class QuitSave;
    }class QuitSave : public QWidget
    {Q_OBJECTpublic:explicit QuitSave(QWidget *parent = nullptr);~QuitSave();private:Ui::QuitSave *ui;// 串口对象QSerialPort* mySerialPort;// QSettings 对象QSettings*   mySettings;/* ui 初始化 */void ui_Init(void);void loadConfig(void);/* 保存配置 */void saveConfig(void);
    };#endif // QUITSAVE_H

    该文件与 方法一 中文件没有什么不同。

  2. quitsave.cpp 中进行如下实现:

    #include "quitsave.h"
    #include "ui_quitsave.h"#include <QDebug>QuitSave::QuitSave(QWidget *parent) :QWidget(parent),ui(new Ui::QuitSave)
    {ui->setupUi(this);mySerialPort = new QSerialPort;//    mySettings = new QSettings("config.ini", QSettings::IniFormat);mySettings = new QSettings("MyConfig", "QuitSave");// ui 初始化ui_Init();// 根据配置设置 UIloadConfig();
    }QuitSave::~QuitSave()
    {// 保存配置项saveConfig();delete mySettings;delete mySerialPort;delete ui;
    }/*!*  @File        : quitsave.cpp*  @Brief       : UI 初始化函数*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 10:35:52*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::ui_Init()
    {// 获取串口端口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ui->comboBox->addItem(info.portName() + ":"+ info.description(), info.portName());  // 将端口号以及设备描述信息写入UI}// 添加典型波特率foreach (auto baudRate, QSerialPortInfo::standardBaudRates()) {ui->baundComboBox->addItem(QString::number(baudRate, 10), QString::number(baudRate, 10));}}/*!*  @File        : quitsave.cpp*  @Brief       : 加载配置信息*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 13:11:45*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::loadConfig()
    {QString comx = mySettings->value("com").toString();            // 获取 COM 接口QString baund = mySettings->value("baund").toString();         // 获取 baund 接口QString stop = mySettings->value("stop").toString();           // 获取 stop 接口QString data = mySettings->value("data").toString();           // 获取 data 接口QString check = mySettings->value("check").toString();         // 获取 check 接口/* 获取设备列表 */int count = ui->comboBox->count();                                  // 获取所有元素int index = 0;for(index = 0; index < count; index++) {if (ui->comboBox->itemData(index).toString() == comx)break;}/* 刷新 UI */ui->comboBox->setCurrentIndex(index == count ? 0 : index);ui->baundComboBox->setCurrentText(baund);ui->stopComboBox->setCurrentText(stop);ui->dataComboBoBox->setCurrentText(data);ui->checkComboBox->setCurrentText(check);
    }/*!*  @File        : quitsave.cpp*  @Brief       : 保存配置文件*  @Details     : None*  @Param       : void*  @Return      : void*  @Author      : Liu Jiahao*  @Date        : 2024-08-26 11:20:02*  @Version     : v1.1*  @Copyright   : Copyright By Liu Jiahao, All Rights Reserved**/
    void QuitSave::saveConfig()
    {// 将读取的内容并保存mySettings->setValue("com", ui->comboBox->currentData());                          // 保存端口号mySettings->setValue("baund", ui->baundComboBox->currentText());                   // 保存波特率mySettings->setValue("stop", ui->stopComboBox->currentText());                     // 保存停止位mySettings->setValue("data", ui->dataComboBoBox->currentText());                   // 保存数据位mySettings->setValue("check", ui->checkComboBox->currentText());                   // 保存校验位
    }

根据上述代码所示,我们可以看到,其在类的构造上有以下内容:

mySerialPort = new QSerialPort;//    mySettings = new QSettings("config.ini", QSettings::IniFormat);
mySettings = new QSettings("MyConfig", "QuitSave");// ui 初始化
ui_Init();// 根据配置设置 UI
loadConfig();

这里依旧使用 QSettings 类,但不同的是,这里不再新建 .ini 文件。而使用 应用程序的组织名称应用程序名称 进行初始化,其原始结构如下所示:

QSettings settings("QrganizationName", "ApplicationName");

其中,QrganizationName 表示 应用程序的组织名称,而 ApplicationName 表示 应用程序名称。看不懂的朋友也没有关系,我将会在后面对这部分进行解释。

这里的写法与使用 ini 文件保存的写法不同,其保存数据采用:

mySettings->setValue("com", ui->comboBox->currentData()); 

这里就没有 的概念,而我们直接定义一个 名称 即可。

同时,对于数据的读取操作,如下所示:

QString comx = mySettings->value("com").toString(); 

因此,直接通过 名称 读取即可。而由于返回的是 QVariant 类型,因此需要 toString() 处理。

那么会有朋友好奇,通过这种方法构建,是如何保存数据的。其实 QSettings 不仅可以读写 ini 文件,也可以对 注册表 进行读写。这里我们就是使用了 读写注册表 的形式。

其在注册表中的位置为:HKEY_CURRENT_USER\SOFTWARE\<QrganizationName>\<ApplicationName> 中。在我的示例中,QrganizationName 我定义为 MyConfig,而 ApplicationName 我定义为 QuitSave。其存储位置就在上面提到的注册表中,如下所示:

在这里插入图片描述

正式因为如此,我们才不需要创建任何文件,就可以实现参数的读写操作。在首次进入软件的时候,该注册表不存在,通过 new 一个 QSettings 对象的时候,会自动创建相应的注册表。我们通过访问对应位置的注册表即可看到我们读写的信息。

这种方法的好处在于隐藏了我们的保存配置文件,且通过二次打包之后仍然能够正常使用。目前据我所知,这也是大多数软件采取的方式,其他方式,欢迎大佬指出。另外,对于账号密码等敏感信息最好不要采取这种方式,毕竟注册表也并非不可见。

3.2 运行结果

在二次打包之后运行效果如下所示:

在这里插入图片描述

可以看到,在初次对 串口设备 以及 波特率 进行设置之后,再次启动软件,其已经设置为我们退出之前的状态。


四、写在最后

本文介绍了 如何在退出 Qt 的时候保用户配置信息,并提供了两种解决方案供大家参考

本文中的代码后续会逐步开源,欢迎关注,敬请期待!!!

欢迎广大读者提出问题以及修改意见,本人看到后会给予回应,欢迎留言,后续会逐步进行开源!!!
另外,由于文章是作者手打的文字,有些地方可能文字会出错,望谅解,也可私信联系我,我对其进行更改。

  • 个人CSDN账号:刘梓谦_-CSDN博客

  • Gitee:刘佳豪 (liu-jiahaohappy) - Gitee.com

  • GitHub:Jiahao-Liu29 (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/414595.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吹爆上海交大的大模型实战教程!!非常详细收藏我这一篇就够了

各位好&#xff0c;这里是DASOU 今天分享一个上海交大的免费的大模型课程&#xff0c;有相关教程文档和Slides&#xff0c;目前是1.6K星标&#xff0c;还是挺火的 项目动机 《动手学大模型》系列编程实践教程&#xff0c;由上海交通大学2024年春季《人工智能安全技术》课程&…

MySQL集群

一、Mysql 在服务器中的部署方法 1.1源码安装 下载依赖性 dnf install cmake gcc-c openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen.x86_64 解压压缩包并安装 tar zxf mysql-boost-5.7.44.tar.gz cd /root/mysql-5.7.44 cmake \ -DCM…

java写入word表格(poi-tl)

1.导入依赖 <!--poi-tl--> <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.0</version> </dependency>2.代码 自己创建模板。放在&#xff08;resource/file&#xff09;…

非标机械设计项目“规范”笔记

2.自动化设备开发特点与技术文件输出 2.1自动化设备 自动化设备 工业自动化设备类型&#xff1a;标准自动化、非标自动化 载具和治具 焊接治具---汽车行业用的多 压装、压合治具---3C行业 治具种类&#xff1a; 电木&#xff1a;测试治具箱体&#xf…

工作5年,没听过MySQL半同步复制,是我的问题吗?

目录 一、存储高可用二、读写分离三、解决主从复制延迟问题的几种方案1、写操作后的读操作指定发给数据库主服务器2、读从机失败后再读一次主机3、关键业务读写操作全部指向主机&#xff0c;非关键业务采用读写分离4、压缩与批量传输5、优化从库的查询性能6、优化网络延迟7、调…

构建大师:深入理解Linux下的Make和Makefile

引言 在软件开发的世界里&#xff0c;构建过程是一项繁琐而重要的任务。无论是简单的脚本还是复杂的软件项目&#xff0c;都需要一种方式来自动化编译、链接以及测试等过程。在Linux环境下&#xff0c;Make工具和它的配置文件——Makefile&#xff0c;成为了许多开发者构建项目…

RuoYi-Vue 最新 SpringBoot3 前后端分离版本源码分析

RuoYi-Vue 最新 SpringBoot3 前后端分离版本源码分析 RuoYi-Vue 本地环境部署若依菜单类型权限管理SpringSecurity 配置登录接口(认证管理)Authentication 认证token的生成 权限控制 异步任务管理操作日志数据权限 RuoYi-Vue 本地环境部署 直接去 gitee 上拉取最新版本即可&am…

<Rust>egui学习之小部件(三):如何为窗口UI元件设置布局(间隔、水平、垂直排列)?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第三篇博…

C++和OpenGL实现3D游戏编程【连载7】——文字和汉字的显示

1、本节实现的内容 上一节我们讨论了纹理在二维平面内不规则图形贴图的相关基础操作,本节我们开始了解游戏里文字以及汉字的显示方法。本节课我们将从基本的ASCII字符显示,拓展到中文字符的显示,最后再讲到纹理字符的显示,并对各种文字显示方法的优缺点和使用场景进行分析…

使用Masscan扫描器进行信息搜集

Masscan 是一款极为高效的端口扫描工具&#xff0c;以其卓越的扫描速度和大规模扫描能力而著称。该工具不仅支持 TCP 和 UDP 协议的扫描&#xff0c;还允许用户根据需求灵活指定多个目标和端口。Masscan 通过采用先进的网络性能优化技术&#xff0c;充分利用操作系统的资源和多…

基于北斗+自组网技术的光伏电场人员位置监控系统优化方案

一、方案背景 1.1 用户需求 随着我国经济的快速发展&#xff0c;光伏电场等新能源项目的建设日益增多。然而&#xff0c;这些项目往往位于偏远地区&#xff0c;通信基础设施不完善&#xff0c;导致施工人员在作业过程中难以与外界保持实时联系。特别是在无人区或信号弱的地区…

【Qt 事件】—— 详解Qt事件处理

目录 &#xff08;一&#xff09;事件介绍 &#xff08;二&#xff09;事件的处理 &#xff08;三&#xff09;按键事件 3.1 单个按键 3.2 组合按键 &#xff08;四&#xff09;鼠标事件 4.1 鼠标单击事件 4.2 鼠标释放事件 4.3 鼠标双击事件 4.4 鼠标移动事件 4.5…

101.SAP MII功能详解(15)Workbench-Transaction Logic(Iterator)

目录 1.Logic->Iterator 2.演示 配置连接 Iterator使用示例 1.Logic->Iterator 您可以使用此操作迭代循环浏览List&#xff0c;迭代是指遍历某个List数据结构&#xff0c;逐个访问其元素的过程。迭代使用的场景不多。 2.演示 配置连接 Iterator使用示例 数据源是Lis…

Qt:玩转QPainter序列九(文本,文本框,填充)

前言 继续承接序列八 正文 1. drawImage系列函数 绘制图像 inline void drawImage(const QPoint &p, const QImage &image); 作用: 在指定的点 p 上绘制 QImage 图像。图像的左上角将对齐到 p 点。 inline void drawImage(int x, int y, const QImage &image,…

[001-07-001].Redis7缓存双写一致性之更新策略探讨

1、面试题&#xff1a; 1.只要使用缓存&#xff0c;就可能会涉及到redis缓存与数据库双存储双写&#xff0c;只要是双写&#xff0c;就存在数据一致性问题&#xff0c;那么是如何解决数据一致性问题的2.双写一致性&#xff0c;你先动缓存redis还是数据库MySQL&#xff0c;哪一个…

新能源汽车超级电容和电池能量管理系统的simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 电池模型 4.2 电池荷电状态&#xff08;SOC&#xff09;估算 4.3 超级电容器模型 4.4 能量管理 5.完整工程文件 1.课题概述 新能源汽车的能量管理系统&#xff08;Energy Management System, EMS…

中国艺术孙溟㠭凿篆《无用之用》

孙溟㠭凿篆作品《无用之用》 这方作品是孙溟㠭先生用凿木的方式凿刻出来的&#xff0c;呈现出了凿痕的效果&#xff0c;与众不同。 孙溟㠭凿篆《无用之用》 孙溟㠭凿篆《无用之用》 万般皆有所用&#xff0c;取其长补余短&#xff0c;无用之用是为大用&#xff0…

JS实现高度不等的列表虚拟滚动加载

当我们拿到后台返回的1万条数据展示时&#xff0c;如果完全渲染不仅渲染的时间很长&#xff0c;也会导致浏览器性能变差&#xff0c;使用过程中还可能会导致卡顿&#xff0c;使用体验变差。 就需要我们想办法优化这种情况&#xff0c;这个时候使用虚拟滚动加载就能很好的避免这…

ESXi服务器无法安装Windows11:“不符合此版本的Windows所需最低系统要求“

目录 一、问题描述1.使用环境2.问题截图3.问题解析 二、解决方法Ⅰ1.按 ShiftF10 弹出命令提示符2.在弹出的Dos框中输入regedit&#xff0c;回车&#xff0c;进入注册表。3.打开HKEY_LOCAL_MACHINE\SYSTEM\Setup&#xff0c;并新建 LabConfig 的项&#xff0c;在 LabConfig 下创…

SAP 查询中间表

可以看到如下代码中&#xff0c;查询了底表zdbconn&#xff0c;又查了中间表ZTFI0072 DATA: gv_dbs(20) ,go_exc_ref TYPE REF TO cx_sy_native_sql_error,gv_error_text TYPE string,lv_count TYPE syst_index.SELECT SINGLE conntxtFROM zdbconn INTO gv_dbsWHERE sy…