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
Forum Updated to NodeBB v4.3 + New Features

QMap exposed as QProperty gives qml undefined

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmapqml qmljson
2 Posts 2 Posters 476 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