Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Is there a way to expose an existing C++ object to a specific QML module as a singleton?

Is there a way to expose an existing C++ object to a specific QML module as a singleton?

Scheduled Pinned Locked Moved Unsolved General and Desktop
qt6qmlsingletonregistertypemodule
9 Posts 4 Posters 304 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.
  • B Offline
    B Offline
    bibasmall
    wrote on 1 Apr 2025, 11:32 last edited by bibasmall 4 Jan 2025, 11:39
    #1

    I learned that using qmlRegisterSingletonInstance is not recommended in Qt6. But I'm having trouble replacing the following with QML_SINGLETON:

    void Application::registerObjects()
    {
        qmlRegisterSingletonInstance("Core.AppSettings", 1, 0, "AppSettings", &settings);
        qmlRegisterSingletonInstance("Network.Server", 1, 0, "Server", &server);
        qmlRegisterSingletonInstance("Core.Util", 1, 0, "Util", &util);
    }
    

    I want to expose the fields of the class Application as singletons to QML, but I need them to be in the certain modules.
    The documentation does not explain whether there is any way to expose an existing object to a specific module.
    I'm using Qt 6.8.2 and CMake.

    R 1 Reply Last reply 2 Apr 2025, 13:35
    0
    • J Offline
      J Offline
      JoeCFD
      wrote on 2 Apr 2025, 12:08 last edited by
      #2

      Singletons are visible to all modules across the app, right?

      B 1 Reply Last reply 2 Apr 2025, 17:29
      0
      • B bibasmall
        1 Apr 2025, 11:32

        I learned that using qmlRegisterSingletonInstance is not recommended in Qt6. But I'm having trouble replacing the following with QML_SINGLETON:

        void Application::registerObjects()
        {
            qmlRegisterSingletonInstance("Core.AppSettings", 1, 0, "AppSettings", &settings);
            qmlRegisterSingletonInstance("Network.Server", 1, 0, "Server", &server);
            qmlRegisterSingletonInstance("Core.Util", 1, 0, "Util", &util);
        }
        

        I want to expose the fields of the class Application as singletons to QML, but I need them to be in the certain modules.
        The documentation does not explain whether there is any way to expose an existing object to a specific module.
        I'm using Qt 6.8.2 and CMake.

        R Offline
        R Offline
        Redman
        wrote on 2 Apr 2025, 13:35 last edited by Redman 4 Feb 2025, 13:37
        #3
        This post is deleted!
        1 Reply Last reply
        0
        • R Offline
          R Offline
          Redman
          wrote on 2 Apr 2025, 13:43 last edited by
          #4

          https://doc.qt.io/qt-6/qml-singleton.html#exposing-an-existing-object-as-a-singleton

          I think what you are looking for is at the end of this paragraph.

          1 Reply Last reply
          0
          • J JoeCFD
            2 Apr 2025, 12:08

            Singletons are visible to all modules across the app, right?

            B Offline
            B Offline
            bibasmall
            wrote on 2 Apr 2025, 17:29 last edited by
            #5

            @JoeCFD
            No, I want them to be visible if a specific module is imported. For example, I expect Server to be available when importing Network.Server. This can be achieved when using macros QML_ELEMENT QML_SINGLETON in your class and qt_add_qml_module in CMake , but the problem is, the instance is created by the QML engine and the object lives in js. I want the instance created in C++ to be exposed to QML.
            @Redman
            I don't understand how exactly I should put my singletons in certain modules. In the example, the singleton is in the same module as SingletonForeign.

            J 1 Reply Last reply 2 Apr 2025, 17:46
            0
            • B bibasmall
              2 Apr 2025, 17:29

              @JoeCFD
              No, I want them to be visible if a specific module is imported. For example, I expect Server to be available when importing Network.Server. This can be achieved when using macros QML_ELEMENT QML_SINGLETON in your class and qt_add_qml_module in CMake , but the problem is, the instance is created by the QML engine and the object lives in js. I want the instance created in C++ to be exposed to QML.
              @Redman
              I don't understand how exactly I should put my singletons in certain modules. In the example, the singleton is in the same module as SingletonForeign.

              J Offline
              J Offline
              JoeCFD
              wrote on 2 Apr 2025, 17:46 last edited by
              #6

              @bibasmall I guess you want to create an instance of the class in a specific module, but not with singleton which will be accessible everywhere. If that is the case, register the class and create an instance of the class(Server) when needed in the top qml file of the module?

              B 1 Reply Last reply 2 Apr 2025, 19:14
              0
              • J JoeCFD
                2 Apr 2025, 17:46

                @bibasmall I guess you want to create an instance of the class in a specific module, but not with singleton which will be accessible everywhere. If that is the case, register the class and create an instance of the class(Server) when needed in the top qml file of the module?

                B Offline
                B Offline
                bibasmall
                wrote on 2 Apr 2025, 19:14 last edited by
                #7

                @JoeCFD
                From an architectural point of view I would prefer to make classes like Server, Logger, AppSettings etc. singletons. qmlRegisterSingletonInstance allows to hide such qml-exposed singletons in modules by setting URI. But the fresh documentation warns against using qmlRegisterSingletonInstance, that's why I'm interested in best practices.

                R 1 Reply Last reply 3 Apr 2025, 05:42
                0
                • B bibasmall
                  2 Apr 2025, 19:14

                  @JoeCFD
                  From an architectural point of view I would prefer to make classes like Server, Logger, AppSettings etc. singletons. qmlRegisterSingletonInstance allows to hide such qml-exposed singletons in modules by setting URI. But the fresh documentation warns against using qmlRegisterSingletonInstance, that's why I'm interested in best practices.

                  R Offline
                  R Offline
                  Redman
                  wrote on 3 Apr 2025, 05:42 last edited by Redman 4 Mar 2025, 05:51
                  #8

                  @bibasmall Okay so, you want to instantiate the singleton in c++, use it in c++ (maybe) but more importantly make it available under qml only when using the corresponding import statement?

                  Thats what I do a lot in my app.

                  CMakeLists

                  qt_add_qml_module(${PROJECT_NAME}
                      URI "singleton.app"
                      VERSION 1.0
                      SOURCES
                          src/Singleton.h
                          src/Singleton.cpp
                  )
                  

                  Singleton

                  class DLL_EXPORT Singleton: public QObject {
                     Q_OBJECT
                     QML_ELEMENT
                     QML_SINGLETON
                     Q_DISABLE_COPY_MOVE(Singleton)
                  public:
                  
                     static void init(QQmlEngine* engine);
                     static void destroy();
                     static bool initialized();
                     Q_INVOKABLE static void func1();
                  
                     /*!
                      * \brief create This function is called when accessing this class through
                      * qml under the hood. By creating the Singleton in c++ we get the same
                      * instance in qml. Only works in same thread
                      *  \param qmlEngine
                      *  \param engine
                      * \return
                      */
                     static inline Singleton*
                     create(QQmlEngine* qmlEngine, QJSEngine* engine) {
                        // The instance has to exist before it is used. We cannot replace it.
                        Q_ASSERT(s_instance.get());
                  
                        // There can only be one engine accessing the singleton.
                        if (m_engine)
                           Q_ASSERT(qmlEngine == m_engine);
                        else
                           m_engine = qmlEngine;
                  
                        // Explicitly specify C++ ownership so that the engine doesn't delete
                        // the instance.
                        QJSEngine::setObjectOwnership(s_instance.get(), QJSEngine::CppOwnership);
                        return s_instance.get();
                     }
                  
                   private:
                     explicit Singleton(QObject* parent = nullptr);
                     static inline std::unique_ptr<Singleton> s_instance = nullptr;
                  
                     /*!
                      * \brief s_engine the QmlEngine this singleton will be accessed from
                      */
                     inline static QQmlEngine* m_engine = nullptr;
                  }
                  
                  void
                  Singleton::init(QQmlEngine* engine) {
                     if (s_instance)
                        return;
                  
                  // I set the QGuiApplication as parent, since static storage duration should roughly equal the lifetime of QGuiApplication
                     s_instance.reset(new Singleton(QGuiApplication::instance()));
                     m_engine = engine;
                  
                  }
                  
                  void
                  Singleton::destroy() {
                     s_instance.reset();
                  }
                  
                  bool
                  Singleton::initialized() {
                  // Simplified logic for this example
                     return s_instance;
                  }
                  
                  void
                  Singleton::func1() {
                  // whatever
                  }
                  

                  and then use it in my main.cpp like so

                     Singleton::init();
                     if (!Singleton::initialized()) {
                        qCritical() << QStringLiteral("Singleton not initialized");
                        return EXIT_FAILURE;
                     }
                  

                  and in qml like this

                  import singleton.app 1.0
                  
                  Item {
                     id:root
                     Component.onCompleted: {
                        Singleton.func1()
                     } 
                  

                  If you want these kind of import paths

                  void Application::registerObjects()
                  {
                      qmlRegisterSingletonInstance("Core.AppSettings", 1, 0, "AppSettings", &settings);
                      qmlRegisterSingletonInstance("Network.Server", 1, 0, "Server", &server);
                      qmlRegisterSingletonInstance("Core.Util", 1, 0, "Util", &util);
                  }
                  

                  I assume you have to

                  qt_add_qml_module(${PROJECT_NAME}
                      URI "core.util"
                      VERSION 1.0
                      SOURCES
                          src/UtilSingleton.h
                          src/UtilSingleton.cpp
                  )
                  

                  I can only assume that this is the intended way of building modular qml modules.

                  A 1 Reply Last reply 3 Apr 2025, 17:28
                  1
                  • R Redman
                    3 Apr 2025, 05:42

                    @bibasmall Okay so, you want to instantiate the singleton in c++, use it in c++ (maybe) but more importantly make it available under qml only when using the corresponding import statement?

                    Thats what I do a lot in my app.

                    CMakeLists

                    qt_add_qml_module(${PROJECT_NAME}
                        URI "singleton.app"
                        VERSION 1.0
                        SOURCES
                            src/Singleton.h
                            src/Singleton.cpp
                    )
                    

                    Singleton

                    class DLL_EXPORT Singleton: public QObject {
                       Q_OBJECT
                       QML_ELEMENT
                       QML_SINGLETON
                       Q_DISABLE_COPY_MOVE(Singleton)
                    public:
                    
                       static void init(QQmlEngine* engine);
                       static void destroy();
                       static bool initialized();
                       Q_INVOKABLE static void func1();
                    
                       /*!
                        * \brief create This function is called when accessing this class through
                        * qml under the hood. By creating the Singleton in c++ we get the same
                        * instance in qml. Only works in same thread
                        *  \param qmlEngine
                        *  \param engine
                        * \return
                        */
                       static inline Singleton*
                       create(QQmlEngine* qmlEngine, QJSEngine* engine) {
                          // The instance has to exist before it is used. We cannot replace it.
                          Q_ASSERT(s_instance.get());
                    
                          // There can only be one engine accessing the singleton.
                          if (m_engine)
                             Q_ASSERT(qmlEngine == m_engine);
                          else
                             m_engine = qmlEngine;
                    
                          // Explicitly specify C++ ownership so that the engine doesn't delete
                          // the instance.
                          QJSEngine::setObjectOwnership(s_instance.get(), QJSEngine::CppOwnership);
                          return s_instance.get();
                       }
                    
                     private:
                       explicit Singleton(QObject* parent = nullptr);
                       static inline std::unique_ptr<Singleton> s_instance = nullptr;
                    
                       /*!
                        * \brief s_engine the QmlEngine this singleton will be accessed from
                        */
                       inline static QQmlEngine* m_engine = nullptr;
                    }
                    
                    void
                    Singleton::init(QQmlEngine* engine) {
                       if (s_instance)
                          return;
                    
                    // I set the QGuiApplication as parent, since static storage duration should roughly equal the lifetime of QGuiApplication
                       s_instance.reset(new Singleton(QGuiApplication::instance()));
                       m_engine = engine;
                    
                    }
                    
                    void
                    Singleton::destroy() {
                       s_instance.reset();
                    }
                    
                    bool
                    Singleton::initialized() {
                    // Simplified logic for this example
                       return s_instance;
                    }
                    
                    void
                    Singleton::func1() {
                    // whatever
                    }
                    

                    and then use it in my main.cpp like so

                       Singleton::init();
                       if (!Singleton::initialized()) {
                          qCritical() << QStringLiteral("Singleton not initialized");
                          return EXIT_FAILURE;
                       }
                    

                    and in qml like this

                    import singleton.app 1.0
                    
                    Item {
                       id:root
                       Component.onCompleted: {
                          Singleton.func1()
                       } 
                    

                    If you want these kind of import paths

                    void Application::registerObjects()
                    {
                        qmlRegisterSingletonInstance("Core.AppSettings", 1, 0, "AppSettings", &settings);
                        qmlRegisterSingletonInstance("Network.Server", 1, 0, "Server", &server);
                        qmlRegisterSingletonInstance("Core.Util", 1, 0, "Util", &util);
                    }
                    

                    I assume you have to

                    qt_add_qml_module(${PROJECT_NAME}
                        URI "core.util"
                        VERSION 1.0
                        SOURCES
                            src/UtilSingleton.h
                            src/UtilSingleton.cpp
                    )
                    

                    I can only assume that this is the intended way of building modular qml modules.

                    A Offline
                    A Offline
                    afalsa
                    wrote on 3 Apr 2025, 17:28 last edited by
                    #9

                    @Redman cool 😎

                    1 Reply Last reply
                    0

                    1/9

                    1 Apr 2025, 11:32

                    • Login

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