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

Qt中使用QSettings数据或结构体到INI文件

一、QSettings 概述

QSettings 是 Qt 框架提供的持久化配置管理类,用于存储和读取应用程序的配置数据(如用户偏好、窗口大小、最近打开文件等)。支持多种存储格式(如 INI 文件、注册表、JSON 等),跨平台使用,无需手动处理文件路径或格式差异。


二、核心功能

跨平台支持

  • Windows:默认使用注册表(HKEY_CURRENT_USER)。
  • macOS/iOS:使用属性列表(.plist 文件)。
  • Linux/Unix:默认使用 INI 文件(~/.config/组织名/应用名.conf)。

存储格式

  • QSettings::IniFormat:读写 INI 文件。
  • QSettings::NativeFormat:自动选择平台默认格式。
  • QSettings::registerFormat():自定义格式(如 JSON)。

数据层次结构

  • 支持分组(beginGroup()/endGroup())和键值对(setValue()/value())。

三、基本用法

初始化与存储

QSettings settings("MyCompany", "MyApp");  // 组织名和应用名  
settings.setValue("window/size", QSize(800, 600));  // 存储窗口大小  
settings.setValue("recentFiles", QStringList{"file1.txt", "file2.txt"});  // 存储列表  

读取与默认值

QSize size = settings.value("window/size", QSize(400, 300)).toSize();  // 读取并设默认值  
QStringList files = settings.value("recentFiles").toStringList();  // 读取列表  

分组管理

settings.beginGroup("network");  
settings.setValue("proxyEnabled", true);  
settings.endGroup();  // 结束分组  

四、高级特性

1、同步与原子性

  • sync():强制将内存数据写入磁盘(通常自动调用)。
  • atomicSync():确保写入操作的原子性(避免文件损坏)。

2、监听变化

  • 信号 QSettings::valueChanged(需手动检查变化)。

3、自定义存储路径

QSettings settings("/path/to/config.ini", QSettings::IniFormat);  // 指定文件路径  

4、结构体数据保存的问题

当尝试直接将结构体保存到INI文件时,会遇到以下问题:

  • 可读性差:保存后的数据会被转换为QByteArray形式的二进制数据,看起来像一堆乱码
  • 直接保存不可行:如果不做特殊处理,Qt不知道如何序列化和反序列化自定义结构体

解决方案:重载输入输出操作符
为了使结构体能够被QSettings正确保存和读取,需要在结构体中重载<<和>>操作符:

struct ClientConfig  {int tabIndex;    QString serverInfo;  // 重载数据流输出操作符friend QDataStream &operator << (QDataStream &out, const ClientConfig &clientConfig) {out << clientConfig.tabIndex;        out << clientConfig.serverInfo;        return out;}// 重载数据流输入操作符friend QDataStream &operator >> (QDataStream &in, ClientConfig &clientConfig) {in >> clientConfig.tabIndex;        in >> clientConfig.serverInfo;        return in;}
};

注册元数据类型
除了重载操作符外,还需要使用Q_DECLARE_METATYPE宏将结构体注册为元数据类型:

Q_DECLARE_METATYPE(ClientConfig)

写入配置

QSettings set("config.ini", QSettings::IniFormat);
ClientConfig clientConfig;// 填充结构体数据
clientConfig.tabIndex = 1;
clientConfig.serverInfo = "example.com";// 写入配置
set.beginGroup("ClientConfig");
set.setValue("clientConfig", QVariant::fromValue(clientConfig)); 
set.endGroup();

读取配置

QSettings set("config.ini", QSettings::IniFormat);
ClientConfig clientConfig;// 读取配置
set.beginGroup("ClientConfig");
clientConfig = set.value("clientConfig").value<ClientConfig>();
set.endGroup();

注意事项

  • 1、可读性问题: 虽然这种方法可以保存结构体,但INI文件中的内容会是二进制形式,不利于直接阅读和修改。如果可读性是首要考虑因素,建议:
    • 将结构体成员分别保存为独立的键值对
    • 或者将结构体转换为JSON等可读格式后再保存
  • 2、版本兼容性: 如果修改了结构体的成员变量,需要确保新旧版本的序列化/反序列化逻辑兼容
  • 3、性能考虑: 对于简单的配置项,直接使用基本类型可能更高效

五、注意事项

  1. 键名区分大小写"Window/Size""window/size" 视为不同键。
  2. 类型安全:读取时需明确转换类型(如 toInt()toString())。
  3. 性能:频繁读写时建议批量操作(beginGroup() 减少键名重复)。

六、源码分享

在这里插入图片描述

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}struct Config  {int tabIndex;QString serverInfo;// 重载数据流输出操作符friend QDataStream &operator << (QDataStream &out, const Config &clientConfig) {out << clientConfig.tabIndex;out << clientConfig.serverInfo;return out;}// 重载数据流输入操作符friend QDataStream &operator >> (QDataStream &in, Config &clientConfig) {in >> clientConfig.tabIndex;in >> clientConfig.serverInfo;return in;}
};Q_DECLARE_METATYPE(Config)void MainWindow::on_btnSave_clicked()
{QSettings set("config.ini", QSettings::IniFormat);Config clientConfig;// 填充结构体数据clientConfig.tabIndex = 1;clientConfig.serverInfo = "example.com";// 写入配置set.beginGroup("Config");set.setValue("Config", QVariant::fromValue(clientConfig));set.endGroup();
}void MainWindow::on_btnRead_clicked()
{QSettings set("config.ini", QSettings::IniFormat);Config clientConfig;// 读取配置set.beginGroup("Config");clientConfig = set.value("Config").value<Config>();qDebug()<<"serverInfo:"<<clientConfig.serverInfo;qDebug()<<"tabIndex:"<<clientConfig.tabIndex;set.endGroup();
}

在这里插入图片描述

http://www.lqws.cn/news/593479.html

相关文章:

  • 边缘人工智能与医疗AI融合发展路径:技术融合与应用前景(下)
  • 区块链存证:数字时代的法律盾牌还是技术乌托邦?
  • 数据结构day5——队列和树
  • 县级智慧水务一体化方案及落地案例PPT(39页)
  • 8.Docker镜像讲解
  • 高强螺栓的计算与选用
  • 深入金融与多模态场景实战:金融文档分块技术与案例汇总
  • Qt时间显示按钮功能详解
  • 【docker】unknown shorthand flag: ‘f‘ in -f See ‘docker --help‘.
  • 实变与泛函题解-心得笔记【16】
  • Electron 应用中的内容安全策略 (CSP) 全面指南
  • MySQL索引深度解析:B+树、B树、哈希索引怎么选?
  • 机器学习在智能金融风险评估中的应用:信用评分与欺诈检测
  • day48
  • C++ 网络编程(13) asio多线程模型IOServicePool
  • CAU数据挖掘实验 表分析数据插件
  • 零信任安全管理系统介绍
  • 安防监控视频汇聚平台EasyCVR v3.7.2版云端录像无法在web端播放的原因排查和解决方法
  • 笔记本电脑怎样投屏到客厅的大电视?怎样避免将电脑全部画面都投出去?
  • Rust 是什么
  • [C#] WPF - 自定义样式(Slider篇)
  • WPF学习(三)
  • 08跨域
  • vue-i18n+vscode+vue 多语言使用
  • Mac 部署Latex OCR并优化体验(打包成App并支持全局快捷键)
  • WebSocket技术全面解析:从历史到实践
  • (Python)Python基础语法介绍(二)(Python基础教学)
  • 老年护理实训室建设方案:打造沉浸式护理实训环境
  • pulseaudio实现音频的网络传输
  • Wireshark TS | 诡异的光猫网络问题