Qt - QSettings实现用户偏好保存

前言

之前在 Android 开发的时候,也有用到用户偏好保存,当时用的是 SharedPreferences

数据最终会被存储为 xml文件,里面存放的是键值对。Qt 也有类似的类,即 QSettings

QSettings

建议先阅读一遍文档 :Qt文档 - QSettings

根据文档所述,QSettings 是一个 平台无关类。之前在 Qt - 跨平台程序打包发布 中提到过Qt跨平台的实现。不了解这个概念的小伙伴可以去看一看。

在这里插入图片描述

创建

//最简,NativeFormat
QSettings settings("MySoft", "Star Runner");

//ini文件
QSettings settings("/home/petra/misc/myapp.ini",
                   QSettings::IniFormat);
//plist文件
QSettings settings("/Users/petra/misc/myapp.plist",
                   QSettings::NativeFormat);
                   

QSettings对象可以在 堆栈 上创建(即使用 new)。构造和销毁QSettings对象`非常快。

存储格式

QSettings 存储的文件格式有:

  • NativeFormat

    使用最适合平台的存储格式存储设置。

    在Windows上,指的是 系统注册表

    在macOS和iOS上,这意味着 CFPreferences API

    在Unix上,即 INI格式的文本配置文件

  • Registry32Format

    仅限Windows:显式访问 32位系统注册表

    在32位Windows上或从64位Windows上的32位应用程序中,其作用与指定NativeFormat相同。

  • Registry64Format

    仅限Windows:显式访问 64位系统注册表

    在32位Windows上或在64位Windows上的64位应用程序中,此操作与指定NativeFormat相同。

  • IniFormat

    将设置存储在 INI文件 中。

    注意:从INI文件读取设置时 不会保留类型信息。所有值将作为 QString 返回。

  • InvalidFormat
    自定义类型;registerFormat() 返回的特殊值。

小结:用户偏好信息,在Windows中此信息通常存储在 系统注册表 中,在macOS和iOS上则存在 属性列表文件 .qlist 中。在Unix系统上,在没有标准的情况下,许多应用程序(包括KDE应用程序)都使用 INI文本文件

QSettings 的 API 基于QVariant(可戳),我们可以使用大多数的类型,例如QString,QRect和QImage。

QSettings存储文件都由一个 QString 和一个 QVariant 组成,该 QString 指定 设置的名称(键),QVariant 存储 与键相关的数据。存储时调用 setValue() 即可。

保存&读取

保存使用的是 setValue()

关于键名,Windows注册表和INI文件使用不区分大小写的键,而macOS和iOS上的CFPreferences API 使用区分大小写的键。

为避免可移植性问题,Qt团队建议遵循以下规则:

  • 始终使用相同的大小写引用相同的键。

  • 请避免使用相同的键名(不区分大小写)。

  • 不要在键名中使用斜杠(“ /”和“ \”);反斜杠字符用于分隔子键。在Windows上,QSettings将“ \”转换为“ /”,从而使它们相同。

我们可以使用’/'字符作为分隔符来形成分层键,类似于 Unix文件路径

	settings.setValue(("mainwindow/size", win->size());());

如果要保存或恢复许多具有相同前缀的设置,可以采用 组机制。用 beginGroup() 指定前缀,结束时调用 endGroup()

注意

  • 如果已经存在具有相同键的设置,则现有值将被新值覆盖。
  • 为了提高效率,更改由事件循环按固定间隔自动保存至永久存储,所以可能不会立即更新到永久存储中。 若想立刻更新,可调用sync()手动提交更改。

读取使用的是 value()

当使用 value()找不到键值时,将返回一个空的QVariant;当然我们也可以在使用value()时传入第二个参数作为 默认值

void MainWindow::writeSettings()
{
    
    
    QSettings settings("MySoft", "Star Runner");
    settings.beginGroup("MainWindows");
    settings.setValue("size",size());
    settings.setValue("pos",pos());
    settings.endGroup();

}

void MainWindow::readSettings()
{
    
    
	QSettings settings("MySoft", "Star Runner");
    settings.beginGroup("MainWindows");
    //参数2:默认值
    resize(settings.value("size",QSize(400,400)).toSize());
    move(settings.value("pos",QPoint(200,200)).toPoint());
    settings.endGroup();
}

要测试给定键是否存在,可调用 contains()

注意:如果使用 beginGroup() 设置了一个组,则将键视为相对于该组的键。

要删除与键关联的设置,可调用 remove()

QSettings settings;
settings.setValue("ape");
settings.setValue("monkey", 1);
settings.setValue("monkey/sea", 2);
settings.setValue("monkey/doe", 4);

settings.remove("monkey");
QStringList keys = settings.allKeys();
// keys: ["ape"]

如果在组中使用,且 key 为空,则将删除该组所以键值对:

QSettings settings;
settings.setValue("ape");
settings.setValue("monkey", 1);
settings.setValue("monkey/sea", 2);
settings.setValue("monkey/doe", 4);

settings.beginGroup("monkey");
settings.remove("");
settings.endGroup();

QStringList keys = settings.allKeys();
// keys: ["ape"]

要获取所有键的列表,可调用 allKeys()

要删除所有键,可调用 clear()

删除与此QSettings对象关联的 主要位置 中的所有条目。

后备位置 的条目不会被删除。

存储位置

QSettings 有一个 备用机制,每次查找键值对的时候它会按顺序查找以下四个位置:

  • User, Application
  • User, Organization
  • System, Application
  • System, Organization

这四个位置是Qt的抽象,使我们无须指定文件路径或注册表路径。

爽
前面说到,claer() 只会删除主位置的所以条目,备用位置不受影响。

若想关闭该机制可调用 setFallbacksEnabled(false)

接下来看一个例子:

    QSettings obj1(("MySoft", "Star Runner");
    
    QSettings obj2(("MySoft");
    
    QSettings obj3((QSettings::SystemScope, "MySoft", "Star Runner");
    
    QSettings obj4((QSettings::SystemScope, "MySoft");

下表列举了以上QSettings的主要位置及备用位置:
在这里插入图片描述
注意主要位置可用于读写,而后备位置仅作为读取时的备胎。

那么这些位置具体指哪里呢?

由于比较琐屑,可自行移步 QSettings平台特定说明

跨平台注意事项

  • Windows系统注册表具有以下限制:子项不能超过255个字符,条目的值不能超过16,383个字符,并且键的所有值都不能超过65535个字符。 要解决这些限制的一种方法是使用存储的设置 IniFormat 而不是 NativeFormat

  • 在Windows上,当使用Windows系统注册表时,QSettings不会保留该值的原始类型。 因此,设置新值时,值的类型可能会更改。

  • 在macOS和iOS上,allKeys()将针对适用于所有应用程序的全局设置返回一些额外的键。这些键可以使用value()读取,但不能更改,只能被显示。 调用 setFallbacksEnabled(false) 将隐藏这些全局设置。

  • 在macOS和iOS上,QSettings使用的CFPreferences API需要Internet域名而不是组织名称。 为了提供统一的API,QSettings从组织名称中派生了一个假域名,该算法在公司名称后附加“ .com”,并用连字符替换空格和其他非法字符。如果要指定其他域名,可使用以下函数:

    QCoreApplication::setOrganizationDomain()
    QCoreApplication::setOrganizationName()
    QCoreApplication::setApplicationName()
    QSettings settings;
    

    另一种解决方案是使用预处理器指令:

    #ifdef Q_OS_MAC Q_OS_MAC
        QSettings settings(("grenoullelogique.fr", "Squash");
    
    #else
        QSettings settings(("Grenoulle Logique", "Squash");
    
    #endif
    
  • 在macOS上,访问权限问题

自定义存储格式

在这里插入图片描述
该函数用于注册自定义存储格式。成功后,返回一个特殊的Format值,然后我们可将其传递给QSettings构造函数。若创建失败,则返回 InvalidFormat

readFuncwriteFunc 参数是指向读取和写入一组键/值对的功能。始终以二进制模式打开读取和写入功能的QIODevice参数。

caseSensitivity 参数指定是否键区分大小写,默认值区分大小写。

默认情况下,如果使用了与组织名称和应用程序名称有关的构造函数,则使用的文件系统位置与IniFormat相同。当然也可使用setPath()指定其他位置。

bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);

int main(int argc, char *argv[])
{
    
    
    const QSettings::Format XmlFormat =
            QSettings::registerFormat("xml", readXmlFile, writeXmlFile);

    QSettings settings(XmlFormat, QSettings::UserScope, "MySoft",
                       "Star Runner");
}

Demo

下面是一个程序退出前自动保存用户设置的demo:

//mainwindow.h
namespace Ui {
    
    
class MainWindow;
}

class MainWindow : public QMainWindow
{
    
    
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void writeSettings();
    void readSettings();
    
private:
    Ui::MainWindow *ui;

protected:
    virtual void closeEvent(QCloseEvent* event)override;
};

//mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    
    
    ui->setupUi(this);
    //下次程序进入时自动加载设置 - 主界面构造函数中读取
    readSettings();
}

void MainWindow::writeSettings()
{
    
    
    QSettings settings("MySoft", "Star Runner");
    settings.beginGroup("MainWindows");
    settings.setValue("size",size());
    settings.setValue("pos",pos());
    settings.endGroup();

}

void MainWindow::readSettings()
{
    
    
    QSettings settings("MySoft", "Star Runner");

    settings.beginGroup("MainWindows");
    //参数2:默认值
    resize(settings.value("size",QSize(400,400)).toSize());
    move(settings.value("pos",QPoint(200,200)).toPoint());
    settings.endGroup();
}

//实现程序退出前保存用户设置 - 重写closeEvent()
void MainWindow::closeEvent(QCloseEvent *event)
{
    
    
    writeSettings();
}

猜你喜欢

转载自blog.csdn.net/weixin_40774605/article/details/106104341