סטנלי גרונן
סטנלי גרונן

Reputation: 2997

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.

Upvotes: 0

Views: 2548

Answers (3)

Joseph Ireland
Joseph Ireland

Reputation: 2505

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

Upvotes: 3

Hayt
Hayt

Reputation: 5370

You can set the setting path with QSettings::setPath

So

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

Should do the trick.

Because you have one ini file it seems and not per user base I think SystemScope is appropriate here

Note: This will set this the location Qt looks for all ini files in your program for the SystemScope so don't use this if you want multiple ini file location for SystemScope

Upvotes: 2

Angel.Risteski
Angel.Risteski

Reputation: 566

You should not send ini files with your application. When user launch the application for first time the app will create the ini file. When you read your settings you should always set a default value. For future use user will override the default values and will use the saved settings.

Change your read function with:

QVariant SettingsManager::read(const QString & key, const QVariant &defaultValue) const
{
    return settings.value(key,defaultValue);
}

and wherever you call the function always provide the default value

Upvotes: 1

Related Questions