groenhen groenhen - 25 days ago 7
C++ Question

Qt: Issue getting the settings ini file from application/executable directory

I am using Qt5.7 on Windows7.

In my current app, I have my own settings manager class, that looks like this:

Header:

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

private:
static QSettings settings;
};


Source 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);
}


My problem is: I gave the app to some friends and probably they launched it with different working directory or something, and the app didn't find the
settings.ini
file, hence it didn't work as it should...

So, the question is: How can I modify the code above to be able to get the
settings.ini
file from the application/executable directory? Obviously, The
settings.ini
file is always in the same folder as the app itself.

Answer

It seems to be a bit strange to see an object with all non-static member functions and all static data members. Are you using it like SettingsManager()::read(...)? It might be more appropriate to just use functions in a namespace, or the singleton pattern.

Anyway, back to the question, you can use QApplication::applicationDirPath() for this purpose. It gets the absolute path to the directory containing the app binary. E.g.

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

gets an absolute path to where you want.

edit: - response to comment about "QApplication doesn't exist error"

it seems like you have an issue with this, since you are using it in a global static initializer, which is run before entering main(), so there is no QApplication yet. You can use a static function variable to delay initialization until the function is called.

You can choose either making a singleton SettingsManager, or just the QSettings (i think that the QSettings is probably weirder as I said above).

Example of QSettings singleton: (needs to be defined in a cpp)

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

if you use that in your functions, it wont create a QSettings until you have called the function, and by then there will be a QApplication instance. But I'd prefer to make the whole class singleton:

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);
}

usage:

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