Qt:从应用程序/可执行目录获取设置 ini 文件的问题

Posted

技术标签:

【中文标题】Qt:从应用程序/可执行目录获取设置 ini 文件的问题【英文标题】:Qt: Issue getting the settings ini file from application/executable directory 【发布时间】:2016-10-28 11:36:22 【问题描述】:

我在 Windows7 上使用 Qt5.7。 在我当前的应用程序中,我有自己的设置管理器类,如下所示:

标题:

class SettingsManager

public:
    void     write(const QString & key, const QVariant & variant);
    QVariant read (const QString & key) const;

private:
    static QSettings settings;
;

来源 cpp:

QSettings SettingsManager::settings("settings.ini", QSettings::IniFormat);

void SettingsManager::write(const QString & key, const QVariant & variant)

    settings.setValue(key, variant);


QVariant SettingsManager::read(const QString & key) const

    return settings.value(key);

我的问题是:我把应用程序给了一些朋友,可能他们用不同的工作目录或其他东西启动了它,应用程序没有找到 settings.ini 文件,因此它没有正常工作。 .

所以,问题是:如何修改上面的代码,以便能够从应用程序/可执行目录中获取settings.ini 文件?显然,settings.ini 文件始终与应用程序本身位于同一文件夹中。

【问题讨论】:

您似乎没有使用绝对路径。 我尝试了类似 ( QCoreApplication::applicationDirPath() + "/settings.ini" ) 的方法,但没有成功。它说的是:请先实例化 QApplication 对象... 你应该有一个QApplicationQCoreApplication 在你的主要地方。在调用静态函数之前,您必须先创建对象。无论如何,您都必须创建一个,所以这没什么大不了的。 main中有一个对象... 您正试图在main 开始运行之前使用设置系统。那是因为您在某处使用设置来初始化全局变量:保证在输入 main 之前初始化这些设置。所以不要那样做,你会没事的。 【参考方案1】:

看到所有非静态成员函数和所有静态数据成员的对象似乎有点奇怪。您是否像SettingsManager()::read(...) 一样使用它? 只使用命名空间中的函数或单例模式可能更合适。

不管怎样,回到问题,你可以使用QApplication::applicationDirPath()来达到这个目的。它获取包含应用程序二进制文件的目录的绝对路径。例如

QString absPath = QDir(QApplication::applicationDirPath()).filePath("settings.ini");    

获取到您想要的位置的绝对路径。

edit: - 回复关于“QApplication 不存在错误”的评论

您似乎对此有疑问,因为您在全局静态初始化程序中使用它,该初始化程序在进入 main() 之前运行,因此还没有 QApplication。您可以使用静态函数变量来延迟初始化,直到调用该函数。

您可以选择制作单例 SettingsManager,也可以只制作 QSettings(我认为 QSettings 可能像我上面所说的更奇怪)。

QSettings 单例示例:(需要在cpp中定义)

QSettings& globalInstance() 
    static QSettings settings(QDir(QApplication::applicationDirPath()).filePath("settings.ini"));
    return settings;

如果你在你的函数中使用它,它不会创建一个 QSettings 直到你调用了这个函数,然后会有一个 QApplication 实例。但我更愿意让整个班级单身:

settingsmanager.h

#include <QApplication>
#include <QDir>
#include <QSettings>

class SettingsManager

public:
    SettingsManager & instance();

    void     write(const QString & key, const QVariant & variant);
    QVariant read (const QString & key) const;

private:
    SettingsManager(const QString & path) : 
        settings(path, QSettings::IniFormat)
    

    QSettings settings;
;

settingsmanager.cpp

#include "settingsmanager.h"

SettingsManager& SettingsManager::instance() 
    static SettingsManager s(QDir(QApplication::applicationDirPath()).filePath("settings.ini"));
    return s;


void SettingsManager::write(const QString & key, const QVariant & variant)

    settings.setValue(key, variant);


QVariant SettingsManager::read(const QString & key) const

    return settings.value(key);

用法:

auto val = SettingsManager::instance().read("key");

【讨论】:

我通常会尽量避免所有看起来像 `ClassName::instance()' 的东西,比如单例或类似的风格,因为它看起来不合适(C++ 中的一些怪异)。如果可能的话,我更喜欢单态——至少它看起来是 C++。这并不意味着我不欣赏您的想法/建议,相反:拇指/投票!谢谢人:) 在这种情况下,我将使用namespace Settings read(..); write(..); ,并在 cpp 中为全局 QSettings 实例函数使用匿名命名空间。这样接口就Settings::read("key"),看起来干净多了。或者把实例函数放在类外,即settings().read("key"); 周末我没有构建环境。我今天早上在办公室尝试了上面的代码,但它似乎不是 100% 正确:我收到以下错误:filePath is not a member of QString... 丹麦的东西很烂 :) 哎呀...我的代码中有 QDir appDir = QApplication::applicationDirPath(); 并假设它会起作用。隐式转换是邪恶的......【参考方案2】:

您可以使用QSettings::setPath设置设置路径

所以

QSettings::setPath(QSettings::IniFormat,QSettings::SystemScope,
                  QCoreApplication::applicationDirPath());

应该做的伎俩。

因为您似乎有一个 ini 文件,而不是每个用户群,我认为SystemScope 适合这里

注意:这将设置此位置 Qt 在您的程序中为SystemScope 查找 所有 ini 文件,因此如果您想要多个 ini,请不要使用它SystemScope 的文件位置

【讨论】:

事实上,应用程序还使用了其他 4 个 INI 文件,但位于一些不同的子文件夹中(这些用于获取某些输入数据文件的当前版本)。如果有的话,您的解决方案/想法将如何影响他们?无论如何,谢谢分享你的想法。竖起大拇指! :) 这会改变 Qt 查找 ini 文件的路径,所以它可能会。但是无论如何我会说你应该把你的文件放在一个中心位置。 (或系统文件的一个地方为每个用户配置另一个地方) 现有的 INI 文件不能放在一起。但我想它们仍然可以像指定路径和文件名一样被显式访问......?我的意思是不必以某种方式干扰上述QSetting::setPath等。 请记住,系统范围内安装的程序可能没有对其安装目录的写入权限。因此,您要么要求每个用户自己安装它,要么将设置写入每个用户的配置位置,请参阅QStandardPaths::writableLocation() 首先启动将复制安装的设置,或者您甚至可以使用 Qt 资源将默认设置构建到应用程序中系统 我今天尝试了上面的建议,但不幸的是它没有奏效......【参考方案3】:

您不应将 ini 文件与您的应用程序一起发送。当用户第一次启动应用程序时,应用程序将创建 ini 文件。当您阅读您的设置时,您应该始终设置一个默认值。为了将来使用,用户将覆盖默认值并使用保存的设置。

改变你的阅读功能:

QVariant SettingsManager::read(const QString & key, const QVariant &defaultValue) const

    return settings.value(key,defaultValue);

无论您在何处调用该函数,始终提供默认值

【讨论】:

不完全是我想要的,但它可能对未来的开发很有用。竖起大拇指:)

以上是关于Qt:从应用程序/可执行目录获取设置 ini 文件的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Qt 应用程序的当前工作目录路径?

QT如何修改编译后产生的可执行文件的路径》

在 Windows 上的 Qt 可执行文件中设置应用程序信息

Qt通过QSttings类读取*.ini配置文件

[QT] 记录一些使用技巧

[QT] 记录一些使用技巧