如何使用QSettings在Qt应用程序中加载设置

时间:2013-01-16 18:56:44

标签: c++ qt qsettings

有两种可能的方式:

  • 将所有设置加载到某个struct
  • 按需加载值

哪种方法更好?

4 个答案:

答案 0 :(得分:8)

这取决于您使用设置文件的方式。您是否希望允许应用程序的用户动态更改文件中的设置(例如.ini文件)?或者必须由GUI设置设置?

如果您使用某些GUI来更改设置,我建议您从静态类加载应用程序开头的主要设置。

void SettingsManager::loadSettings()
{
    // .ini format example
    QSettings settings(FileName, QSettings::IniFormat);

    IntegerSetting = settings.value("SettingName", default).toInt();
    BooleanSetting = settings.value("SettingName", default).toBool();

    // ...
}

然后,由于QSettings优化,按需保存更改后的值没有问题。

/**
  * key is your setting name
  * variant is your value (could be string, integer, boolean, etc.)
  */
void SettingsManager::writeSetting(const QString &key, const QVariant &variant)
{
    QSettings settings(FileName, QSettings::IniFormat);

    settings.setValue(key, variant);
}

答案 1 :(得分:3)

如果您担心,可以将每个逻辑设置组放在界面后面。然后,构建一个使用QSettings按需检索设置的具体类。

如果您发现这是性能瓶颈,请构建一个缓存设置的具体类。 (我从来不需要这样做.QSettings一直很快。)

答案 2 :(得分:2)

QSettings的文档中,它说它已经过优化。

在内部,它将QStrings的地图保存到QVariants。所有访问器方法都非常有用,并且易于使用。

当我使用QSettings时,我将其设置与具有readSettings()writeSettings()功能的示例类似。请在页面的一半左右查看此example

当我调用readSettings()创建QSettings对象时,它会根据需要加载值,并将所有设置保留在某个结构中。

所以在我的main函数中,我确保设置我的应用程序名称和组织名称,并且我也使用QSettings::setFormat,然后在我想访问QSettings之后,我创建了一个QSettings实例默认参数并访问设置。

QSettings s;
int val = s.value("Some_Group/some_setting", default_value).toInt();

// ...

s.setValue("Some_Group/some_setting", val);

答案 3 :(得分:0)

我不会完全回答您的问题,因为您提出的问题是错误的;)您正在询问阅读设置。通过构造QSettings()进行读取并调用QSettings::value()几乎从来不是问题,我的所有测量都表明它非常快,非常接近0毫秒。关于您的问题:我将直接读取数据,即没有中介结构。拥有另一层只是复杂而已,不值得为可能的同步付出努力。现在是真正的问题。

但是,最主要的问题是写入设置。如果您使用本地存储进行设置,这在Windows上也相当快,这是Windows注册表(Windows的默认设置)。注册表是由操作系统优化的,缓存在RAM中,因此写入is也不会引起延迟。但是在Linux上,这似乎是一个非常不同的故事。接下来的内容与Linux有关(在我的情况下为Ubuntu和Kubuntu)。

我没有详细研究Qt的源代码,但是我的所有测量都表明,在进行任何更改后将设置写入磁盘至少需要在普通磁盘上花费约50毫秒,SSD可能会更快。在我看来,当QSettings对象数据已更改且对象被销毁时,或当应用程序事件循环准备好执行某些工作(即不忙于重绘或处理其他事件)时,将调用保存操作。然后将设置刷新到磁盘。

因此,无论您关注的速度如何,我都警告不要调用此QSettings().setValue(key, value);。因为这将导致对象破坏后立即进行保存操作,并导致延迟。

如果仅对设置调用一次保存操作,则节省时间不是问题,例如,关闭应用程序时,您可以轻松地支付50毫秒。但这通常不是您想要的。您希望动态保存应用程序状态。换句话说,当您在应用程序中进行某些更改,然后在不关闭第一个实例的情况下,打开了该应用程序的另一个实例,并且您希望新实例已经具有新的设置。在这种情况下,您必须在进行任何更改后立即保存所有内容,而不仅仅是保存应用程序关闭时。然后,节省时间成为一个大问题。

我怎么做。我创建一个具有静态方法的单例类Settings,并提供与QSettings对象类似的API。在此单例对象中,仅创建一次QSettings对象(实例化QApplication之后),并在应用程序结束时仅销毁一次。在我的代码中,我随时可以调用Settings::value(key)Settings::setValue(key, value)。优点是仅在事件循环准备就绪时才保存设置。当然,这仍然需要50毫秒,但是可以确定的是,它只会被调用一次,并且会保存所有已缓存的更改。与QSettings().setValue(key, value)相比,这是一个很大的改进,#pragma once #include <QSettings> /// Singleton! Create only one instance! class Settings { public: Settings(); ~Settings(); static bool contains(const QString &key); static QVariant value(const QString &key, const QVariant &defaultValue = QVariant()); static void setValue(const QString &key, const QVariant &value); private: static Settings *s_instance; QSettings m_settings; }; 每次都会调用save,并且如果您多次进行这样的调用会阻塞UI。

您当然可以通过多种方式实现单例。我使用的是这个:

settings.h:

#include "settings.h"

Settings *Settings::s_instance = nullptr;

Settings::Settings()
{
    Q_ASSERT(s_instance == nullptr);
    s_instance = this;
}

Settings::~Settings()
{
    Q_ASSERT(s_instance != nullptr);
    s_instance = nullptr;
}

bool Settings::contains(const QString &key)
{
    return s_instance->m_settings.contains(key);
}

QVariant Settings::value(const QString &key, const QVariant &defaultValue)
{
    return s_instance->m_settings.value(key, defaultValue);
}

void Settings::setValue(const QString &key, const QVariant &value)
{
    s_instance->m_settings.setValue(key, value);
}

settings.cpp:

...
Application application; // must be created before settings
Settings settings; // create settings singleton
application.exec() // runs event loop - settings is stored whenever event loop is ready
// settings destroyed here
// application destroyed here
...

main.cpp:

Settings::setValue(key, value);

在其余代码中,只需调用getText()

请注意,即使对于某些时间紧迫的用例,此解决方案也不够好。例如,考虑通过拖动鼠标来调整拆分器或窗口的大小。您希望它平滑并同时保存设置,对吗?为了获得平滑度,您一定不要在拖动过程中保存它,而只能在拖动完成之后保存它。因此,请勿在鼠标移动事件中保存设置。您只想在拖动完成后更改设置。为了实现这一点,您将不得不使用事件过滤器做一些巧妙的技巧,也许继承继承并自定义库存的Qt小部件,或者根据您的需要定制其他东西。但这是不同的故事和不同的问题。