【发布时间】:2019-03-02 08:43:01
【问题描述】:
有没有办法设置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;从文件名派生“路径”容易出错,因为Qt在“路径”来派生文件名,而“魔法”并没有真正记录下来)。
所以我想出的唯一解决方案是:
- 创建了解应用程序可移植性的工厂,
在堆上构造一个
QSettings对象,并使用适当的 构造函数,并返回一个指向它的指针。这有一个缺点 必须管理该动态构造对象的内存, 因此不合理地增加了复杂性。它还添加了另一个实体 这取决于应用程序的可移植性。 - 如上所述,但使用单例。这也增加了多余的
复杂性,同时解决简单的问题。同样在这种情况下
QSettings对象将存在于整个应用程序生命周期中。
所以我有一种感觉,我肯定在这里遗漏了一些东西,我想知道是否有更简单的解决方案来解决这个问题。
旁注:目前,如果应用程序是可移植的,我通过将组织名称设置为“设置”来解决此问题,因此应用程序设置存储在 APP_FOLDER/settings/APP_NAME.ini 中。一个肮脏的黑客,但节省了很多复杂性。无论如何,我实际上并没有在任何地方使用组织名称。
【问题讨论】:
-
你不能只使用
QSettings构造函数来指定full path and format吗? -
如果工厂返回
std::unique_ptr,你也不必关心内存管理...... -
@G.M.我在我的问题中提到了那个构造函数。这是一个可能的解决方案,但它要求使用设置的每一段代码都知道将它们保存在哪里。当一段代码保存到一个地方,而另一个保存到不同的地方时,它就有可能出错。此外,由于有很多地方使用了设置,它添加了很多重复的代码,例如:
if (Globals::appIsPortable) {QSettings s(Globals::settingsPath, QSettings::defaultFormat); /* use settings */ } else {QSettiings s; /*use settings*/};。这可以使用宏来简化,但我不喜欢这个想法。