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. Access QML elements from C++ classes
QtWS25 Last Chance

Access QML elements from C++ classes

Scheduled Pinned Locked Moved Solved QML and Qt Quick
11 Posts 4 Posters 2.9k Views
  • 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.
  • D Offline
    D Offline
    DavidM29
    wrote on last edited by
    #1

    Hello,

    I would like to access all my QML elements from a C++ class wich is not my "main.cpp". I found some examples on the web but only on the "main.cpp". I want to access it from a custom C++ class.

    How can I do that ?

    I'm trying to handle properties from a file that will change value or state of differents QML components. I am able to read property from my file and change the value of the QML components but I'm not able to save the state of the components in the properties file.

    1 Reply Last reply
    0
    • KillerSmathK Offline
      KillerSmathK Offline
      KillerSmath
      wrote on last edited by KillerSmath
      #2

      @DavidM29
      Can you show me an example of how are you trying to do that ?

      Because depending of your implemention, you can expose a c++ object to qml and acess the proprieties of qml components using this object.

      @Computer Science Student - Brazil
      Web Developer and Researcher
      “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

      1 Reply Last reply
      0
      • D Offline
        D Offline
        DavidM29
        wrote on last edited by
        #3

        For example I have a two state option with a label it look like that :

        0_1529410500784_0504c349-7dc1-455c-b3bf-b7a022478e77-image.png

        This is a Component to me wich I called OptionSwitch. My OptionSwitch has 2 properties :

        • The label of the option wich is a String
        • The switch wich is an alias in order to access it states

        From my option page I have implement a Component a FileIO wich is my C++ class to read my text file.
        In my main.cpp I added this line to give access to my FileIO as a component in QML :

            qmlRegisterType<FileIO, 1>("FileIO", 1, 0, "FileIO");
        

        In my QML I just have to set the location of my file and then I access to the value of by calling FileIO functions.

        This is just for one option but I want to handle it in a more generic way. Here is an example of what I want to do :

        Example of properties file :
        "element.property01=value01
        element.property02=value02
        element2.property01=value03
        "

        The QML option page would contains many OptionSwitch for example :

        OptionSwitch{
              id: element
              property01: value01
              property02: value02
        }
        OptionSwitch {
              id: element2
              property01=value03
        }
        

        When I load my QML element I read the value from my file wich works at the moment.
        Then to save I would like to use a button that call my C++ write function.

        When I read my value from my file I use a map of strings where the Key is the name of the property and the value is the value of the property.

        I'm not sure to be very clear on everything, so if I'm not or you want more information please ask me.

        1 Reply Last reply
        0
        • KillerSmathK Offline
          KillerSmathK Offline
          KillerSmath
          wrote on last edited by
          #4

          @DavidM29

          Okay, you could write and read information from .json file but after few time googling, i noticed that QT have a class to work with set and get of properties of application.

          QSettings C++ Documentation

          You could to use the QSettings Class to set and get values of .ini file in your application. But QSettings is a c++ class, so you need to create a custom class and reimplement the methods to be callable from QML.

            1. Create a setting class derived of QSettings
            1. Reimplement the basic methods: setValue, value and construtors
            1. Create a object of custom settings and expose to context of qml

          Below is an example of how you can implement:

          customsettings.h file

          #ifndef CUSTOMSETTINGS_H
          #define CUSTOMSETTINGS_H
          
          #include <QObject>
          #include <QSettings>
          #include <QVariant>
          
          class CustomSettings : public QSettings
          {
              Q_OBJECT
          public:
              CustomSettings(QObject *parent = nullptr);
              CustomSettings(const QString &fileName, QSettings::Format format, QObject *parent = nullptr);
              Q_INVOKABLE void setValue(const QString &key, const QVariant &value);
              Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
          
              Q_INVOKABLE void sync();
          };
          
          #endif // CUSTOMSETTINGS_H
          
          

          customsettings.cpp file

          #include "customsettings.h"
          
          CustomSettings::CustomSettings(QObject *parent) : QSettings(parent)
          {
          
          }
          
          CustomSettings::CustomSettings(const QString &fileName, QSettings::Format format, QObject *parent) : QSettings(fileName, format, parent)
          {
          
          }
          
          void CustomSettings::setValue(const QString &key, const QVariant &value)
          {
              QSettings::setValue(key, value);
          }
          
          QVariant CustomSettings::value(const QString &key, const QVariant &defaultValue) const
          {
              return QSettings::value(key, defaultValue);
          }
          
          void CustomSettings::sync()
          {
              QSettings::sync();
          }
          

          main.cpp file

          #include <QApplication>
          #include <QQmlApplicationEngine>
          #include <QQmlContext>
          #include "customsettings.h"
          
          int main(int argc, char *argv[]) {
              QApplication app(argc, argv);
          
              QCoreApplication::setOrganizationName("YourOrganization");
              QCoreApplication::setOrganizationDomain("yourorganization.com");
              QCoreApplication::setApplicationName("Your Application Name");
          
              CustomSettings settings("mysettings.ini", QSettings::IniFormat);
          
              QQmlApplicationEngine engine;
          
              engine.rootContext()->setContextProperty("settings", &settings);
          
              engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
              if (engine.rootObjects().isEmpty())
                  return -1;
          
              return app.exec();
          }
          

          main.qml file

          import QtQuick 2.4
          import QtQuick.Window 2.1
          import QtQuick.Layouts 1.2
          import QtQuick.Controls 2.0
          
          Window {
              id: window
              width: 800
              height: 600
              minimumHeight: 350
              minimumWidth: 500
              visible: true
              color: "#222222"
          
              function saveSettings(){
                  settings.setValue("nametextfield/text", nameTextField.text);
                  settings.setValue("switch01/checked", switch01.checked);
                  settings.setValue("switch02/checked", switch01.checked);
          
                  settings.sync(); // necessary to force the saving as permanenty data
              }
          
              function loadSettings(){
                  nameTextField.text = settings.value("nametextfield/text", nameTextField.text);
                  switch01.checked = settings.value("switch01/checked", switch01.checked);
                  switch02.checked = settings.value("switch02/checked", switch02.checked);
              }
          
              ColumnLayout{
                  width: 450
                  height: 250
                  anchors.centerIn: parent
          
                  RowLayout{
                      Item{ Layout.fillWidth: true }
          
                      Text {
                          text: "Name: "
                          color: "white"
                      }
                      TextField{
                          id: nameTextField
                          text: "Insert Your Name"
                      }
          
                      Item{ Layout.fillWidth: true }
                  }
          
                  Item{  Layout.fillHeight: true }
          
                  RowLayout{
                      Item{ Layout.fillWidth: true }
          
                      Text {
                          text: "Switch 01: "
                          color: "white"
                      }
                      Switch {
                          id: switch01
                          checked: false
                      }
          
                      Item{ Layout.fillWidth: true }
                  }
          
                  RowLayout{
                      Item{ Layout.fillWidth: true }
          
                      Text {
                          text: "Switch 02: "
                          color: "white"
                      }
                      Switch {
                          id: switch02
                          checked: false
                      }
          
                      Item{ Layout.fillWidth: true }
                  }
          
                  Item{ Layout.fillHeight: true }
          
                  RowLayout{
                      Item{ Layout.fillWidth: true  }
          
                      Button{
                          id: saveButton
                          text : "Save Data"
                          onClicked: window.saveSettings(); // call Save Function
          
                      }
          
                      Button{
                          id: loadButton
                          text: "Load Data"
          
                          onClicked: window.loadSettings(); // call Load Function
                      }
          
                      Button{
                          id: reset
                          text: "Reset Data"
                          onClicked: {
                              switch01.checked = false
                              switch02.checked = false
                              nameTextField.text = "Insert Your Name"
                          }
                      }
          
                      Item{ Layout.fillWidth: true }
                  }
              }
          }
          

          @Computer Science Student - Brazil
          Web Developer and Researcher
          “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

          1 Reply Last reply
          2
          • GrecKoG Offline
            GrecKoG Offline
            GrecKo
            Qt Champions 2018
            wrote on last edited by
            #5

            or http://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html

            1 Reply Last reply
            0
            • D Offline
              D Offline
              DavidM29
              wrote on last edited by DavidM29
              #6

              @KillerSmath
              Thank you for your answer it is a good solution. Almost everything works fine !
              I have only one issue. When I load my settings I do it like that in my QML :

                  
                  Component.onCompleted: {
                      loadSettings()
                  }
              

              But when I do that the value it reads is good but it does not apply it to my component. Here is my loadSettings method :

                 function loadSettings(){
                      console.log(settings.value("Gen/night", night.checked))
                      night.checked = settings.value("Gen/night", night.checked)
                      console.log(night.checked)
                  }
              

              When I launch it the console print : "qml: false" at first so the read value is false (wich is the expected value) then it is supposed to change the state of my component. But it keep its value at true. The console show "qml:true" on the second console.log

              I don't really understand why it behave like that, do you have any clues ?

              1 Reply Last reply
              0
              • KillerSmathK Offline
                KillerSmathK Offline
                KillerSmath
                wrote on last edited by KillerSmath
                #7

                @DavidM29
                This is a problem of convertion between the set and get of data.

                When you use settings.setValue("Name", bool), this boolean is saved as String in .ini file but when you recover this value and tries to convert to bool again, occours a conversion error.

                When you use settings.setValue("Name", bool), this boolean is saved as String in .ini file but when you try to recover, this value is returned as Qvariant of string and because it, occours a conversion error.

                setValue()   ->      value()
                bool         ->      "bool"
                false        ->      "false"
                132442       ->      "132442"
                "121415"     ->      "121415"
                

                Javascript language implements some of ECMA-262 specifications

                http://www.ecma-international.org/ecma-262/5.1/#sec-9.2

                Notice that:

                The result is false if the argument is the empty String (its length is zero); otherwise the result is true.

                Settings QML Type already implement a feature to solve this problem but with limitation.

                Settings QML Type Notes:

                The current implementation is based on QSettings. This imposes certain limitations, such as missing change notifications. Writing a setting value using one instance of Settings does not update the value in another Settings instance, even if they are referring to the same setting in the same category.

                So, if this limitation is a problem for your application, you can implement a feature to fix this problem in c++ QSettings.

                QVariant CustomSettings::value(const QString &key, const QVariant &defaultValue)
                {
                    QVariant value = QSettings::value(key, defaultValue);
                    
                    if (QString(value.typeName()) == "QString" &&  (value.toString() == "false" || value.toString() == "true"))
                        return QVariant(value.toBool());
                    
                    return value;
                }
                

                Extra: if you need to save settings and load in all instances of your application, i recommend you to implement another method of storage as .json that can difference true boolean of "true" string

                References:
                QML engine not implicitly converting a bool-string QVarient to bool property - StackOverFlow

                @Computer Science Student - Brazil
                Web Developer and Researcher
                “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                1 Reply Last reply
                2
                • D Offline
                  D Offline
                  DavidM29
                  wrote on last edited by
                  #8

                  If I wan't to implement another method of storage I will not be able to use QSettings anymore as long as it does not support .json format. Am I wrong ?

                  1 Reply Last reply
                  0
                  • KillerSmathK Offline
                    KillerSmathK Offline
                    KillerSmath
                    wrote on last edited by
                    #9

                    @DavidM29 the problem is not the file type but the Json Sintaxe

                    @Computer Science Student - Brazil
                    Web Developer and Researcher
                    “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                    edipE 1 Reply Last reply
                    1
                    • D Offline
                      D Offline
                      DavidM29
                      wrote on last edited by
                      #10

                      Yes I understand because in .json the string value are encapsulated in " " but to do that I will have to make my own json reader and writer I will not be able to use the QSettings.

                      1 Reply Last reply
                      0
                      • KillerSmathK KillerSmath

                        @DavidM29 the problem is not the file type but the Json Sintaxe

                        edipE Offline
                        edipE Offline
                        edip
                        wrote on last edited by
                        #11

                        @KillerSmath Thank you so much! Very useful answer.

                        1 Reply Last reply
                        0

                        • Login

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