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. What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?

What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
6 Posts 3 Posters 279 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.
  • P Offline
    P Offline
    peter.thompson
    wrote on 27 Mar 2025, 18:39 last edited by peter.thompson
    #1

    I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

    In the meantime, until everything can be replaced with QML, I'm going to have a hybrid application where the majority of my app is still Qt widgets and C++ but there are bits and pieces that are QML contained in QQuickWidgets. In this hybrid context, I am wondering how to interface between the C++ code (defining widgets) and the QML code (defining the contents of a QQuickWidget). I know how to set up C++ classes so that their data is accessible in QML (inheriting from QObject and using QML_ELEMENT along with Q_PROPERTY, Q_INVOKABLE, etc.). But what I would like to know is how I should pass the actual data objects from my C++ code to QML in the first place?

    I've considered the following, but they are both marked as "not recommended" in the official documentation:

    • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
    • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

    Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

    J B 2 Replies Last reply 29 Mar 2025, 07:29
    0
    • P peter.thompson referenced this topic on 27 Mar 2025, 18:39
    • P peter.thompson
      27 Mar 2025, 18:39

      I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

      In the meantime, until everything can be replaced with QML, I'm going to have a hybrid application where the majority of my app is still Qt widgets and C++ but there are bits and pieces that are QML contained in QQuickWidgets. In this hybrid context, I am wondering how to interface between the C++ code (defining widgets) and the QML code (defining the contents of a QQuickWidget). I know how to set up C++ classes so that their data is accessible in QML (inheriting from QObject and using QML_ELEMENT along with Q_PROPERTY, Q_INVOKABLE, etc.). But what I would like to know is how I should pass the actual data objects from my C++ code to QML in the first place?

      I've considered the following, but they are both marked as "not recommended" in the official documentation:

      • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
      • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

      Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

      J Online
      J Online
      jeremy_k
      wrote on 29 Mar 2025, 07:29 last edited by
      #2

      @peter-thompson said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

      I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

      If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

      I've considered the following, but they are both marked as "not recommended" in the official documentation:

      • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
      • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

      I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

      Not injecting into the root context is another matter. The context is the "environment". It's not obvious whether something is there explicitly for the component, or just happens to be around from a parent context.

      Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

      If a singleton makes sense, sure, why not. They can make for extra refactoring and confusion if it turns out there there should be more or less than one. Testing, for example.

      Asking a question about code? http://eel.is/iso-c++/testcase/

      P 2 Replies Last reply 2 Apr 2025, 20:15
      0
      • P peter.thompson
        27 Mar 2025, 18:39

        I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

        In the meantime, until everything can be replaced with QML, I'm going to have a hybrid application where the majority of my app is still Qt widgets and C++ but there are bits and pieces that are QML contained in QQuickWidgets. In this hybrid context, I am wondering how to interface between the C++ code (defining widgets) and the QML code (defining the contents of a QQuickWidget). I know how to set up C++ classes so that their data is accessible in QML (inheriting from QObject and using QML_ELEMENT along with Q_PROPERTY, Q_INVOKABLE, etc.). But what I would like to know is how I should pass the actual data objects from my C++ code to QML in the first place?

        I've considered the following, but they are both marked as "not recommended" in the official documentation:

        • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
        • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

        Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

        B Offline
        B Offline
        Bob64
        wrote on 29 Mar 2025, 11:51 last edited by
        #3

        @peter-thompson I wonder if this thread might be useful. Having relied on setContextProperty while using an older version of Qt until quite recently, I have been trying to catch up on best practices but haven't put it into action yet.

        If you look for the post by ekkescorner in that thread and follow their link, there is some good info on their website.

        This thread may also be of interest. It is mainly concerned with injection of dependencies when Qt singletons are used.

        Also this thread. Look for the post by KH-219Design, who has a pretty rigorous approach to QML-C++ interfacing that might be of interest to you.

        1 Reply Last reply
        0
        • J jeremy_k
          29 Mar 2025, 07:29

          @peter-thompson said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

          I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

          If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

          I've considered the following, but they are both marked as "not recommended" in the official documentation:

          • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
          • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

          I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

          Not injecting into the root context is another matter. The context is the "environment". It's not obvious whether something is there explicitly for the component, or just happens to be around from a parent context.

          Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

          If a singleton makes sense, sure, why not. They can make for extra refactoring and confusion if it turns out there there should be more or less than one. Testing, for example.

          P Offline
          P Offline
          peter.thompson
          wrote on 2 Apr 2025, 20:15 last edited by
          #4

          @jeremy_k said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

          I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

          The warning I was referring to is mentioned in two places: Overview - QML and C++ Integration and Interacting with QML Objects from C++. It says:

          Warning: Although it is possible to access QML objects from C++ and manipulate them, it is not the recommended approach, except for testing and prototyping purposes. One of the strengths of QML and C++ integration is the ability to implement UIs in QML separate from the C++ logic and dataset backend, and this fails if the C++ side starts manipulating QML directly. Such an approach also makes changing the QML UI difficult without affecting its C++ counterpart.

          I think it may be specifically referring to navigating the QML object tree and setting properties/invoking methods on child objects. So it might not apply to working with the root object alone. In fact, I am leaning toward using this method since (as you mentioned) it is basically equivalent to having a parent QML component set the properties of its child components. And in the hybrid app I may be working with, the Qt widget is the parent of the QQuickWidget/QML component.

          If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

          This is an interesting idea that I had not considered. How would this work? Would I still use QQuickWidgets to integrate the QML with the widgets visually/structurally, and just pass the already-created QQmlEngine instance that they should use?

          J 1 Reply Last reply 3 Apr 2025, 02:09
          0
          • J jeremy_k
            29 Mar 2025, 07:29

            @peter-thompson said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

            I currently have a Qt widgets application written in C++. I'd like to transition this application to using QML for the user interface. However, it is a large application, so I can't transition the whole thing all at once. Instead, I'm planning to use QQuickWidgets to start replacing particular widgets with QML. With this approach, I should be able to gradually extend the scope of what is covered with QML until the entire application uses it. This will start with the leaves of the application (i.e. the most highly nested widgets) and move inward toward the root of the application.

            If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

            I've considered the following, but they are both marked as "not recommended" in the official documentation:

            • Getting the root object using QQuickWidget::rootObject() and setting its properties using QObject::setProperty().
            • Getting the root context using QQuickWidget::rootContext() and setting context properties using QQmlContext::setContextProperty().

            I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

            Not injecting into the root context is another matter. The context is the "environment". It's not obvious whether something is there explicitly for the component, or just happens to be around from a parent context.

            Another option I've seen is to pass an instance of a singleton class using qmlRegisterSingletonInstance(). But I'm not sure this would apply to my specific scenario.

            If a singleton makes sense, sure, why not. They can make for extra refactoring and confusion if it turns out there there should be more or less than one. Testing, for example.

            P Offline
            P Offline
            peter.thompson
            wrote on 2 Apr 2025, 22:49 last edited by peter.thompson 4 Feb 2025, 22:49
            #5

            @Bob64 Thanks for all those links! There's some good info in there, which I'll have to look through more thoroughly. The last link, with the post by KH-219Design seems especially interesting. I had heard about the concept of MVVM in a QML app, but hadn't looked into it in detail. That could be a good option to keep most of the code in C++. And as a result it might make it easier to interact with the rest of the widgets application.

            1 Reply Last reply
            0
            • P peter.thompson
              2 Apr 2025, 20:15

              @jeremy_k said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

              I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

              The warning I was referring to is mentioned in two places: Overview - QML and C++ Integration and Interacting with QML Objects from C++. It says:

              Warning: Although it is possible to access QML objects from C++ and manipulate them, it is not the recommended approach, except for testing and prototyping purposes. One of the strengths of QML and C++ integration is the ability to implement UIs in QML separate from the C++ logic and dataset backend, and this fails if the C++ side starts manipulating QML directly. Such an approach also makes changing the QML UI difficult without affecting its C++ counterpart.

              I think it may be specifically referring to navigating the QML object tree and setting properties/invoking methods on child objects. So it might not apply to working with the root object alone. In fact, I am leaning toward using this method since (as you mentioned) it is basically equivalent to having a parent QML component set the properties of its child components. And in the hybrid app I may be working with, the Qt widget is the parent of the QQuickWidget/QML component.

              If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

              This is an interesting idea that I had not considered. How would this work? Would I still use QQuickWidgets to integrate the QML with the widgets visually/structurally, and just pass the already-created QQmlEngine instance that they should use?

              J Online
              J Online
              jeremy_k
              wrote on 3 Apr 2025, 02:09 last edited by
              #6

              @peter-thompson said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

              @jeremy_k said in What is the best practice for passing C++ data objects to QML that is contained in a QQuickWidget?:

              I had not noticed a warning against setting properties in root objects. That's the method I prefer, as it resembles what I would generally do if instantiating the component as a node of a larger QML tree. Properties of the root component can serve as documentation of inputs. Multiple property initialization functions such as QQmlComponent::setInitialProperties() might be more efficient.

              The warning I was referring to is mentioned in two places: Overview - QML and C++ Integration and Interacting with QML Objects from C++. It says:

              Warning: Although it is possible to access QML objects from C++ and manipulate them, it is not the recommended approach, except for testing and prototyping purposes. One of the strengths of QML and C++ integration is the ability to implement UIs in QML separate from the C++ logic and dataset backend, and this fails if the C++ side starts manipulating QML directly. Such an approach also makes changing the QML UI difficult without affecting its C++ counterpart.

              I think it may be specifically referring to navigating the QML object tree and setting properties/invoking methods on child objects. So it might not apply to working with the root object alone.

              That's my reading, and hence the subsequent surprise. I generally attempt to treat children of widget instances similarly.

              If there are a significant number of QQuickWidgets, consider instantiating an independent QQmlEngine, rather than relying on each widget to create its own.

              This is an interesting idea that I had not considered. How would this work? Would I still use QQuickWidgets to integrate the QML with the widgets visually/structurally, and just pass the already-created QQmlEngine instance that they should use?

              Exactly. The engine comes with a component cache, network access manager, and some additional configurable features that can be more efficient to reuse.

              Asking a question about code? http://eel.is/iso-c++/testcase/

              1 Reply Last reply
              0

              2/6

              29 Mar 2025, 07:29

              4 unread
              • Login

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