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. QMap exposed as QProperty gives qml undefined

QMap exposed as QProperty gives qml undefined

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmapqml qmljson
2 Posts 2 Posters 809 Views 1 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.
  • SavizS Offline
    SavizS Offline
    Saviz
    wrote on last edited by
    #1

    I am attempting to develop a singleton C++ class and make it accessible to QML using the qmlRegisterSingletonType() method. This class is designed to manage a QMap<QString, QString> property containing pairs of colors. I intend to utilize these colors in my QML elements for theme-related purposes.

    AppTheme.hpp

    #ifndef APPTHEME_H
    #define APPTHEME_H
    
    #include <QObject>
    #include <QMap>
    #include <QQmlEngine>
    #include <QFile>
    #include <QJsonDocument>
    #include <QJsonObject>
    #include <QJsonArray>
    
    class AppTheme : public QObject
    {
        Q_OBJECT
        Q_DISABLE_COPY(AppTheme)
    public:
        explicit AppTheme(QObject *parent = nullptr);
        ~AppTheme();
    
        // Fields;
    private:
        static AppTheme* m_Instance;
        QMap<QString, QString> m_Colors;
    
        Q_PROPERTY(QMap<QString, QString> Colors READ Colors WRITE setColors NOTIFY ColorsChanged FINAL)
    
        // Methods;
    public:
        static AppTheme* instance(QQmlEngine *engine, QJSEngine *scriptEngine);
        void loadFromJsonFile(const QString &filePath);
    
        QMap<QString, QString> Colors() const;
        void setColors(const QMap<QString, QString> &newColors);
    
        // Signals;
    signals:
        void ColorsChanged();
    
        // Slots;
    public slots:
        void extractColors(const QString &filePath);
    };
    
    #endif // APPTHEME_H
    
    

    AppTheme.cpp

    #include "AppTheme.h"
    
    AppTheme* AppTheme::m_Instance = nullptr;
    
    AppTheme::AppTheme(QObject *parent)
        : QObject{parent}
        , m_Colors()
    {}
    
    AppTheme::~AppTheme()
    {}
    
    QMap<QString, QString> AppTheme::Colors() const
    {
        return m_Colors;
    }
    
    void AppTheme::setColors(const QMap<QString, QString> &newColors)
    {
        if (m_Colors == newColors)
            return;
        m_Colors = newColors;
        emit ColorsChanged();
    }
    
    void AppTheme::extractColors(const QString &filePath)
    {
        loadFromJsonFile(filePath);
    }
    
    AppTheme *AppTheme::instance(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine);
        Q_UNUSED(scriptEngine);
    
        if (!m_Instance)
        {
            m_Instance = new AppTheme();
        }
    
        return(m_Instance);
    }
    
    void AppTheme::loadFromJsonFile(const QString &filePath)
    {
        QMap<QString, QString> map;
    
        QFile file(filePath);
    
        if (!file.open(QIODevice::ReadOnly))
        {
            qWarning() << "Could not open JSON file:" << filePath;
    
            return;
        }
    
        QByteArray jsonData = file.readAll();
        file.close();
    
        QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
        QJsonObject rootObject = jsonDoc.object();
    
        // Assuming your JSON structure is an object with key-value pairs
        for (auto it = rootObject.begin(); it != rootObject.end(); ++it)
        {
            // Assuming keys and values are both strings
            map[it.key()] = it.value().toString();
        }
    
        // Using QProperty binding.
        setColors(map);
    
        qDebug() << map;
        qDebug() << m_Colors;
    }
    
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include "AppTheme.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        qmlRegisterSingletonType<AppTheme>("AppTheme", 1, 0, "AppTheme", &AppTheme::instance);
    
        const QUrl url(u"qrc:/QTodo/main.qml"_qs);
        QObject::connect(
            &engine,
            &QQmlApplicationEngine::objectCreated,
            &app,
            [url](QObject *obj, const QUrl &objUrl) {
                if (!obj && url == objUrl)
                    QCoreApplication::exit(-1);
            },
            Qt::QueuedConnection);
        engine.load(url);
    
    
        return app.exec();
    }
    
    

    main.qml

    import QtQuick
    import QtQuick.Controls
    
    ApplicationWindow {
        id: root
    
        width: 640
        height: 800
    
        visible: true
        title: qsTr("QTodo")
    
        Component.onCompleted: {
    
            AppTheme.extractColors("C:/Users/Saviz/Desktop/QML projects/QTodo/QTodo/colors.json");
            
            // This gives qml undefined error.
            console.log(AppTheme.Colors["CustomColor"])
        }
    }
    

    It effectively reads the file and generates the correct QMap. However, when attempting to use it in QML to set the color property of my rectangle, I encounter undefined behavior in QML. The debugging output is as follows:

    QMap(("CustomColor", "#ff0000"))
    QMap(("CustomColor", "#ff0000"))
    qml: undefined

    The QMap is correctly generated, but in QML, it appears unable to recognize the string as a color.

    JSON file

    {
        "CustomColor": "#ff0000"
    }
    

    Any reason why this is happening?

    MesrineM 1 Reply Last reply
    0
    • SavizS Saviz

      I am attempting to develop a singleton C++ class and make it accessible to QML using the qmlRegisterSingletonType() method. This class is designed to manage a QMap<QString, QString> property containing pairs of colors. I intend to utilize these colors in my QML elements for theme-related purposes.

      AppTheme.hpp

      #ifndef APPTHEME_H
      #define APPTHEME_H
      
      #include <QObject>
      #include <QMap>
      #include <QQmlEngine>
      #include <QFile>
      #include <QJsonDocument>
      #include <QJsonObject>
      #include <QJsonArray>
      
      class AppTheme : public QObject
      {
          Q_OBJECT
          Q_DISABLE_COPY(AppTheme)
      public:
          explicit AppTheme(QObject *parent = nullptr);
          ~AppTheme();
      
          // Fields;
      private:
          static AppTheme* m_Instance;
          QMap<QString, QString> m_Colors;
      
          Q_PROPERTY(QMap<QString, QString> Colors READ Colors WRITE setColors NOTIFY ColorsChanged FINAL)
      
          // Methods;
      public:
          static AppTheme* instance(QQmlEngine *engine, QJSEngine *scriptEngine);
          void loadFromJsonFile(const QString &filePath);
      
          QMap<QString, QString> Colors() const;
          void setColors(const QMap<QString, QString> &newColors);
      
          // Signals;
      signals:
          void ColorsChanged();
      
          // Slots;
      public slots:
          void extractColors(const QString &filePath);
      };
      
      #endif // APPTHEME_H
      
      

      AppTheme.cpp

      #include "AppTheme.h"
      
      AppTheme* AppTheme::m_Instance = nullptr;
      
      AppTheme::AppTheme(QObject *parent)
          : QObject{parent}
          , m_Colors()
      {}
      
      AppTheme::~AppTheme()
      {}
      
      QMap<QString, QString> AppTheme::Colors() const
      {
          return m_Colors;
      }
      
      void AppTheme::setColors(const QMap<QString, QString> &newColors)
      {
          if (m_Colors == newColors)
              return;
          m_Colors = newColors;
          emit ColorsChanged();
      }
      
      void AppTheme::extractColors(const QString &filePath)
      {
          loadFromJsonFile(filePath);
      }
      
      AppTheme *AppTheme::instance(QQmlEngine *engine, QJSEngine *scriptEngine)
      {
          Q_UNUSED(engine);
          Q_UNUSED(scriptEngine);
      
          if (!m_Instance)
          {
              m_Instance = new AppTheme();
          }
      
          return(m_Instance);
      }
      
      void AppTheme::loadFromJsonFile(const QString &filePath)
      {
          QMap<QString, QString> map;
      
          QFile file(filePath);
      
          if (!file.open(QIODevice::ReadOnly))
          {
              qWarning() << "Could not open JSON file:" << filePath;
      
              return;
          }
      
          QByteArray jsonData = file.readAll();
          file.close();
      
          QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
          QJsonObject rootObject = jsonDoc.object();
      
          // Assuming your JSON structure is an object with key-value pairs
          for (auto it = rootObject.begin(); it != rootObject.end(); ++it)
          {
              // Assuming keys and values are both strings
              map[it.key()] = it.value().toString();
          }
      
          // Using QProperty binding.
          setColors(map);
      
          qDebug() << map;
          qDebug() << m_Colors;
      }
      
      

      main.cpp

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include <QQmlContext>
      
      #include "AppTheme.h"
      
      int main(int argc, char *argv[])
      {
          QGuiApplication app(argc, argv);
      
          QQmlApplicationEngine engine;
      
          qmlRegisterSingletonType<AppTheme>("AppTheme", 1, 0, "AppTheme", &AppTheme::instance);
      
          const QUrl url(u"qrc:/QTodo/main.qml"_qs);
          QObject::connect(
              &engine,
              &QQmlApplicationEngine::objectCreated,
              &app,
              [url](QObject *obj, const QUrl &objUrl) {
                  if (!obj && url == objUrl)
                      QCoreApplication::exit(-1);
              },
              Qt::QueuedConnection);
          engine.load(url);
      
      
          return app.exec();
      }
      
      

      main.qml

      import QtQuick
      import QtQuick.Controls
      
      ApplicationWindow {
          id: root
      
          width: 640
          height: 800
      
          visible: true
          title: qsTr("QTodo")
      
          Component.onCompleted: {
      
              AppTheme.extractColors("C:/Users/Saviz/Desktop/QML projects/QTodo/QTodo/colors.json");
              
              // This gives qml undefined error.
              console.log(AppTheme.Colors["CustomColor"])
          }
      }
      

      It effectively reads the file and generates the correct QMap. However, when attempting to use it in QML to set the color property of my rectangle, I encounter undefined behavior in QML. The debugging output is as follows:

      QMap(("CustomColor", "#ff0000"))
      QMap(("CustomColor", "#ff0000"))
      qml: undefined

      The QMap is correctly generated, but in QML, it appears unable to recognize the string as a color.

      JSON file

      {
          "CustomColor": "#ff0000"
      }
      

      Any reason why this is happening?

      MesrineM Offline
      MesrineM Offline
      Mesrine
      wrote on last edited by
      #2

      @Saviz
      I think is not possible to expose a QMap directly to QML,
      https://doc.qt.io/qt-6/qtqml-cppintegration-data.html#sequence-type-to-javascript-array

      Maybe one should use a QVariantMap
      https://doc.qt.io/qt-6/qtqml-cppintegration-data.html#qvariantlist-and-qvariantmap-to-javascript-array-and-object

      1 Reply Last reply
      1
      • SavizS Saviz has marked this topic as solved on

      • Login

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