防止 QSettings 将组织名称添加到 QSettings::setPath() 设置的路径中

Prevent QSettings from adding organization name to the path set by QSettings::setPath()

有没有办法设置 QSettings 存储的实际默认路径(有或没有文件名),并防止 QSettings 将组织名称等内容附加到该路径?要求 QSettings 的进一步使用保持不变并且不知道设置存储路径。

考虑用例。在我的主要我有以下代码:

QApplication a(argc, argv);

...

QCoreApplication::setApplicationName(APP_NAME);
QCoreApplication::setOrganizationDomain(MY_DOMAIN);
QCoreApplication::setOrganizationName(MY_ORGANIZATION);
QCoreApplication::setApplicationVersion(APP_VERSION);

...

a.exec();

在我的整个项目中,我都像这样使用 QSettings

QSettings settings;

settings.setValue(somePath, someValue);

someOtherValue = settings.value(someOtherPath, someDefault);

现在我需要使应用程序可移植。所以我将 main 中的代码更改为:

QApplication a(argc, argv);

...

QCoreApplication::setApplicationName(APP_NAME);
QCoreApplication::setOrganizationDomain(MY_DOMAIN);
QCoreApplication::setOrganizationName(MY_ORGANIZATION);
QCoreApplication::setApplicationVersion(APP_VERSION);

if (PORTABLE) {
    QSettings::setDefaultFormat(QSettings::IniFormat);
    QString settingsPath = a.applicationDirPath() + "/settings";
    QSettings::setPath(QSettings::defaultFormat(), QSettings::UserScope, settingsPath);
    QSettings::setPath(QSettings::defaultFormat(), QSettings::SystemScope, settingsPath);
}

...

a.exec();

但不是将设置写入 APP_PATH/settings/,而是实际位置变为 APP_PATH/settings/ORGANIZATION_NAME/,在我看来这有点太丑陋了。

我想设置 QSettings 以将设置存储在特定位置。用户代码必须不知道存储位置的变化。理想情况下在 main 中设置 QSettings,并使用进一步使用默认构造函数构造的对象。

我发现只有 QSettings(const QString &fileName, QSettings::Format format, QObject *parent = nullptr) 构造函数才能真正设置存储位置。所有其他构造函数不断向路径中添加内容。而且由于我不希望用户代码知道应用程序的可移植性,所以每次都使用不同的构造函数不是一种选择。

我考虑过像这样子类化 QSettings 来修复 setPath():

class Settings : public QSettings {
private:
    static QString mPath = "";

public:
    Settings(QObject *parent = nullptr) :
        QSettings(
            mPath.isEmpty() ? 
            QSettings() : 
            QSettings(mPath, Settings::defaultFormat, parent)
        )
    {}

    static void setPath(QSettings::Format format, QSettings::Scope scope, const QString &path)
    {
        mPath = path;
        QSettings::setPath(format, scope, path);
    }
} 

但这是不可能的,因为 QSettings 没有复制构造函数。在每种情况下都使用 QSettings(mPath, Settings::defaultFormat, parent) 构建基础,但是如果尚未设置 mPath 则将其设置为默认路径,也不能这样做,因为没有方法可以获取默认 QSettings存储路径(有setPath,没有getPath;有getFileName,没有setFileName;从fileName导出"path"容易出错因为 Qt 添加了一些 "magic",比如那个组织名称,到 "path" 派生文件名,而 "magic" 并没有真正记录)。

所以我想到的唯一解决方案是:

  1. 创建一个了解应用程序可移植性的工厂, 使用适当的方法在堆上构造一个 QSettings 对象 构造函数,returns 指向它的指针。这有一个缺点 必须管理那个动态构造的对象的内存, 因此不合理地增加了复杂性。它还添加了另一个实体 这取决于应用程序的可移植性。
  2. 如上所述,但使用单例。这也增加了多余的 复杂性,同时解决简单的问题。同样在这种情况下 QSettings 对象将在整个应用程序生命周期内存在。

所以我觉得我肯定在这里遗漏了一些东西,我想知道是否有更简单的解决方案来解决这个问题。

旁注:目前我通过将我的组织名称设置为 "settings"(如果该应用程序是可移植的)来解决此问题,因此应用程序设置存储在 APP_FOLDER/settings/APP_NAME.ini 中。一个肮脏的黑客,但节省了很多复杂性。无论如何,我真的不会在任何地方使用组织名称。

我的理解是,您本质上希望 QSettings 根据是否已设置特定路径以两种方式之一构建。

您可以创建一个 class,而不是从 QSettings 继承,它带有指向成员 -> 运算符的重载指针,returns 指向 QSettings 的指针实例。这样 QSettings 的初始化可以推迟到需要时,并利用已设置的任何信息。

class settings {
public:
  static void set_path (QSettings::Format format, QSettings::Scope scope, const QString &path)
    {
      s_path = path;
      QSettings::setPath(format, scope, path);
    }
  QSettings *operator-> ()
    {
      return get_settings();
    }
private:
  QSettings *get_settings ()
    {
      if (!m_settings) {
        if (s_path.isEmpty()) {
          m_settings = std::make_unique<QSettings>();
        } else {
          m_settings = std::make_unique<QSettings>(s_path, QSettings::defaultFormat());
        }
      }
      return m_settings.get();
    }
  static QString             s_path;
  std::unique_ptr<QSettings> m_settings;
};

QString settings::s_path = "";

与默认值一起使用时 settings/values...

settings settings;
std::cout << "\nsettings file path is [" << settings->fileName() << "]";

上面给出了类似...

settings file path is [/home/<user>/.config/Unknown Organization/appname.conf]

使用...明确设置所需路径

settings::set_path(QSettings::defaultFormat(), QSettings::SystemScope, app.applicationDirPath() + "/settings.ini");
settings settings;
std::cout << "\nsettings file path is [" << settings->fileName() << "]";

给...

settings file path is [/home/<user>/scratch/settings.ini]