My task is to create a QSettings
wrapper class (wrapping is mostly needed by QML) which I can reach everywhere from the model, too.
The obvious choice is a static global instance of this class. However the problem is with this approach is that it's destroyed after main
, after QApplication
is destroyed, thus giving me the following warning:
QApplication::qAppName: Please instantiate the QApplication object first
Here is a simplified, sample code showing a really simple wrapper, and the destruction phases:
#include <QCoreApplication>
#include <QDebug>
#include <QGlobalStatic>
#include <QSettings>
#include <QTimer>
class Settings: public QObject
{
public:
~Settings() { qDebug() << "~Settings"; }
QSettings settings;
};
Q_GLOBAL_STATIC(Settings, globalSettings)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){qDebug() << "~QCoreApplication aboutToQuit";});
QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){globalSettings->settings.setValue("Hi", 2);});
QObject::connect(&app, &QCoreApplication::destroyed, [](){qDebug() << "~QCoreApplication destroyed";});
QTimer::singleShot(0, &app, SLOT(quit()));
return app.exec();
}
It prints out the following:
~QCoreApplication aboutToQuit
~QCoreApplication destroyed
~Settings
QApplication::qAppName: Please instantiate the QApplication object first
My question is: providing, in my program QSettings
is used after QCoreApplication::aboutToQuit
is emitted but before QCoreApplication::destroyed
, how can I avoid this warning?
Using
QSettings
I've used
QSettings
in pretty much every project I've ever made. Here is the pattern that I tend to use it:in main.cpp
Then anytime you are about to access
QSettings
, you just do this:Everything gets saved in the User Scope in an INI text file. It will be located in Windows under
C:/Users/<username>/AppData/Roaming/MyOrg/MyApp.ini
.This usage of
QSettings
(IMHO) is very clean, doesn't require global variables or static references and is very fast and efficient. And it is very readable.Now to be able to have things load settings at the right times, and not get the errors you mentioned in your question, see the initial example in the links below:
http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application
http://doc.qt.io/qt-5/qtwidgets-mainwindows-application-example.html
It works much better in the timeline of a Qt application and works great. I tend to make a
readSettings
andwriteSettings
for most of my GUI classes and for a number of my backend classes.readSettings
happens when the widget has itsshowEvent
or constructor happen and thewriteSettings
happens in thecloseEvent
. Also if I have a dedicated settings dialog, I emit a signal to have any affected classes toreadSettings
, right after the settings dialog writes those specific settings.If you use the QML port of QSettings, it also uses the Organization name and Application name and the default format of QSettings to pick its filename and location.
http://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html
I believe the default functionality of that QML component is just to read the setting when the component is created, and to write the setting whenever QML changes it. So to change it from C++ and have it recognized by QML, you should probably use the standard QML/C++ methods out there such as:
http://doc.qt.io/qt-5/qtqml-cppintegration-topic.html
And lastly if I am planning on installing defaults for a program that are decided for a build and I don't want to hardcode them, I hand write an INI file and have the installer place it in the system scope location:
C:/ProgramData/MyOrg/MyApp.ini
And in the case that the settings of your program are more complex than what you want to store in an INI file, I would look into using
QJson
, and the SaveGame example.Hope that helps.