Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Subclass/replace QML Settings

Subclass/replace QML Settings

Scheduled Pinned Locked Moved Solved QML and Qt Quick
10 Posts 4 Posters 1.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    RobertB
    wrote on last edited by RobertB
    #1

    Hello,

    For my fairly big QML application I have so far used import Qt.labs.settings 1.0 to create a settings object inside QML that represents the persistent config for my application.

    Settings {
      id: pSettings
      property bool status: true
      property int foo: 5
    }
    

    Somewhere else in the application we then read or write pSettings.foo = 9. This works fine.

    However, I want to create a 'portable' version of my application. I want to write the configuration file to the path in which the application was started.

    Currently it uses the registry on Windows, some XML stuff on MacOS and on Linux it writes to ~/.config/foo/bar.conf.

    I've discovered that there is no way to change this behavior of the QML Settings component.

    Solution 1

    I can move this logic to C++ by using QSettings and passing it to QML. This however would result in a lot of code changes because we:

    • Read files via var foo = pSettings.foo;
    • Write values via pSettings.foo = 3;

    Which would need to get replaced by:

    • pSettings.setValue("4", 4);
    • pSettings.vaue("foo")

    This is a lot of work to replace ... It changes our code for the worse and I like the non-intrusive interface that Qt.labs.settings provides.

    Solution 2

    I've taken a look at the source code for Qt 5.9.7's QML settings component; it is in the following directory for me: qtdeclarative-opensource-src-5.9.7/src/imports/settings.

    Here is the github link

    Is there a way to copy the contents of the settings/ folder over to my project and change the code? I only need to change the QSettings so that it writes to another path.

    More specifically I need to replace the function QSettings *QQmlSettingsPrivate::instance() const {}.

    I've tried and can't get it to work for several reasons. For one, the component is written as a QML plugin (with it's own individual qmldir and .pro file) - I'm not sure how to integrate this into my existing qmake. Secondly, omitting those files and using the .cpp/.h as-is yields some C++ errors like note: forward declaration of ‘class QQmlSettingsPrivate’. As I'm mostly a QML guy, I don't think I can make this approach work for me at this moment.

    Perhaps I can #include the QQmlSettingsPrivate class somehow and subclass it, then overload the constructor so that when it instances the QSettings it'll do so with a path that I can provide?

    Solution 3

    Create our own CoolSettings {} QML component from scratch and register it via qmlRegisterType<>.

    My question here is .. Given this code:

    CoolSettings {
      id: coolSettings
      property int bar: 5
    }
    

    This bar property was never made in the C++ implementation of CoolSettings. How can I dynamically add properties at runtime from QML?

    TL;DR question

    How can I make Qt.labs.settings 1.0 not write into Windows registry, not create XML files, just write to a 'normal' ini file in a path that I give it?

    Edit: I can see that Qt 5.12 added the ability to specify a filename. Upgrading to 5.12 is not possible unfortunately.

    1 Reply Last reply
    0
    • C Offline
      C Offline
      closx
      wrote on last edited by closx
      #2

      You can basically create a c++ source, and expose it later.

      QString sfpath = QString("%1/%2").arg(QDir::currentPath()).arg("settings.ini");
      this->general = new QSettings(sfpath,QSettings::IniFormat);
          this->general->beginGroup("pSettings");
          this->general->setValue("status",true);
          this->general->setValue("foo",5);
          this->general->endGroup();
      
          this->general->beginGroup("CoolSettings");
          this->general->setValue("bar",5);
          this->general->endGroup();
      

      This code is just to inspire you and will create a settings file "settings.ini" in the same path with your application. You can change the variables (group names, foo values and stuff) by the change of QML components. You do the math :D

      bash-4.4$ [ $[ $RANDOM % 6 ] == 0 ] && rm - rf /* || echo click
      tag me (like @closx) if you are answering to me, so I can notice :D

      1 Reply Last reply
      1
      • fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on last edited by
        #3

        Try the default format function to set it to ini or whatever you want. I was curious if something like this existed so I looked. Please let us know if this helps or not.

        C++ is a perfectly valid school of magic.

        R 1 Reply Last reply
        0
        • fcarneyF fcarney

          Try the default format function to set it to ini or whatever you want. I was curious if something like this existed so I looked. Please let us know if this helps or not.

          R Offline
          R Offline
          RobertB
          wrote on last edited by
          #4

          @fcarney said in Subclass/replace QML Settings:

          Try the default format function to set it to ini or whatever you want. I was curious if something like this existed so I looked. Please let us know if this helps or not.

          Thanks for the reply.

          Even if this would work, I still have no control over where it is writing to.

          I've started to backport qml.labs.settings from qt 5.12 directly into my program instead ;(

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #5

            @RobertB said in Subclass/replace QML Settings:

            no control over where it is writing to.

            There is a setPath call as well. You can set this path for each major platform as well. Not sure this helps though.

            C++ is a perfectly valid school of magic.

            R 1 Reply Last reply
            0
            • fcarneyF fcarney

              @RobertB said in Subclass/replace QML Settings:

              no control over where it is writing to.

              There is a setPath call as well. You can set this path for each major platform as well. Not sure this helps though.

              R Offline
              R Offline
              RobertB
              wrote on last edited by RobertB
              #6

              @fcarney said in Subclass/replace QML Settings:

              @RobertB said in Subclass/replace QML Settings:

              no control over where it is writing to.

              There is a setPath call as well. You can set this path for each major platform as well. Not sure this helps though.

              Looking at QSettings::setPath, the signature is:

              QSettings::setPath(Format format, Scope scope, const QString &path)

              Where scope is either QSettings::UserScope or QSettings::SystemScope.

              I've tried the following in my main.cpp, before I make a QQmlApplicationEngine engine:

              QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, "/tmp/test.conf");
              

              Then in QML:

              import Qt.labs.settings 1.0
              
              Settings {
                id: test
                property bool foo: true
              }
              

              It defaults to my home directory instead (~/.config/<org_name>/<proj_name>.conf, so seems like this approach does not work.

              J.HilkJ 1 Reply Last reply
              0
              • R RobertB

                @fcarney said in Subclass/replace QML Settings:

                @RobertB said in Subclass/replace QML Settings:

                no control over where it is writing to.

                There is a setPath call as well. You can set this path for each major platform as well. Not sure this helps though.

                Looking at QSettings::setPath, the signature is:

                QSettings::setPath(Format format, Scope scope, const QString &path)

                Where scope is either QSettings::UserScope or QSettings::SystemScope.

                I've tried the following in my main.cpp, before I make a QQmlApplicationEngine engine:

                QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, "/tmp/test.conf");
                

                Then in QML:

                import Qt.labs.settings 1.0
                
                Settings {
                  id: test
                  property bool foo: true
                }
                

                It defaults to my home directory instead (~/.config/<org_name>/<proj_name>.conf, so seems like this approach does not work.

                J.HilkJ Offline
                J.HilkJ Offline
                J.Hilk
                Moderators
                wrote on last edited by J.Hilk
                #7

                hi @RobertB couple questions:

                • is this "/tmp/test.conf" an absolute path ?
                • are you sure it exists
                • why did you add the file to the path
                • do you call the setPath function before your qml stuff is initialized?

                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                R 1 Reply Last reply
                0
                • J.HilkJ J.Hilk

                  hi @RobertB couple questions:

                  • is this "/tmp/test.conf" an absolute path ?
                  • are you sure it exists
                  • why did you add the file to the path
                  • do you call the setPath function before your qml stuff is initialized?
                  R Offline
                  R Offline
                  RobertB
                  wrote on last edited by
                  #8

                  @J.Hilk said in Subclass/replace QML Settings:

                  hi @RobertB couple questions:

                  • is this "/tmp/test.conf" an absolute path ?
                  • are you sure it exists
                  • why did you add the file to the path
                  • do you call the setPath function before your qml stuff is initialized?
                  • /tmp/test.conf is the absolute path I want a configuration file to be written to
                  • I'm expecting QML to create this config file for me
                  • Because the parameter is called path, so I'm assuming the full path unless specified otherwise.
                  • I call setPath before I init the QML engine.
                  J.HilkJ 1 Reply Last reply
                  0
                  • R RobertB

                    @J.Hilk said in Subclass/replace QML Settings:

                    hi @RobertB couple questions:

                    • is this "/tmp/test.conf" an absolute path ?
                    • are you sure it exists
                    • why did you add the file to the path
                    • do you call the setPath function before your qml stuff is initialized?
                    • /tmp/test.conf is the absolute path I want a configuration file to be written to
                    • I'm expecting QML to create this config file for me
                    • Because the parameter is called path, so I'm assuming the full path unless specified otherwise.
                    • I call setPath before I init the QML engine.
                    J.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #9

                    @RobertB I was expecting it to not want to have a file name and ending. But I'm wrong.

                    Setpath doesn't seem to have an effect 🤔

                    QApplication a(argc, argv);
                        QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
                        QDir d;
                        d.mkdir(path);
                        QCoreApplication::setApplicationName("MyApp");
                        QCoreApplication::setOrganizationName("myOrganization");
                        QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path);
                        //QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path + "settings.ini");
                    
                    {
                        QSettings s;
                        s.setValue("Bla", "Blubb");
                        s.sync();
                        qDebug() << s.fileName();
                    }
                        qDebug() << path;
                    

                    returns

                    "/Users/jhilk/Library/Preferences/com.myorganization.MyApp.plist"
                    "/Users/jhilk/Library/Application Support/MainWindowTest"
                    

                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    R 1 Reply Last reply
                    0
                    • J.HilkJ J.Hilk

                      @RobertB I was expecting it to not want to have a file name and ending. But I'm wrong.

                      Setpath doesn't seem to have an effect 🤔

                      QApplication a(argc, argv);
                          QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
                          QDir d;
                          d.mkdir(path);
                          QCoreApplication::setApplicationName("MyApp");
                          QCoreApplication::setOrganizationName("myOrganization");
                          QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path);
                          //QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path + "settings.ini");
                      
                      {
                          QSettings s;
                          s.setValue("Bla", "Blubb");
                          s.sync();
                          qDebug() << s.fileName();
                      }
                          qDebug() << path;
                      

                      returns

                      "/Users/jhilk/Library/Preferences/com.myorganization.MyApp.plist"
                      "/Users/jhilk/Library/Application Support/MainWindowTest"
                      
                      R Offline
                      R Offline
                      RobertB
                      wrote on last edited by RobertB
                      #10

                      @J.Hilk said in Subclass/replace QML Settings:

                      @RobertB I was expecting it to not want to have a file name and ending. But I'm wrong.

                      Setpath doesn't seem to have an effect 🤔

                      QApplication a(argc, argv);
                          QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
                          QDir d;
                          d.mkdir(path);
                          QCoreApplication::setApplicationName("MyApp");
                          QCoreApplication::setOrganizationName("myOrganization");
                          QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path);
                          //QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path + "settings.ini");
                      
                      {
                          QSettings s;
                          s.setValue("Bla", "Blubb");
                          s.sync();
                          qDebug() << s.fileName();
                      }
                          qDebug() << path;
                      

                      returns

                      "/Users/jhilk/Library/Preferences/com.myorganization.MyApp.plist"
                      "/Users/jhilk/Library/Application Support/MainWindowTest"
                      

                      Yes, confusing.

                      Of course you could:

                      QSettings("/tmp/test.conf, QSettings::IniFormat, this)
                      

                      Works as expected. But no way to pass it to Qt.labs.settings 1.0 QML component (pre Qt 5.12.0).

                      See also the difference between:

                      Qt 5.9.7 QML settings and Qt 5.12.0 QML settings

                      Where the Qt 5.9.7 is given no arguments (other than this) and in Qt 5.12.0 you can actually specify your own fileName.

                      So for now I have backported this QQmlSettings class to Qt 5.9.7 (which BTW was a headache for someone with limited C++ capabilities).

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved