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. How to dynamically pair qml objects with c++ objects
Forum Updated to NodeBB v4.3 + New Features

How to dynamically pair qml objects with c++ objects

Scheduled Pinned Locked Moved Solved QML and Qt Quick
29 Posts 5 Posters 400 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.
  • J Offline
    J Offline
    Jay_emissary
    wrote 6 days ago last edited by
    #1

    Greetings,
    I'm trying to dynamically create qml objects that should be paired with a corresponding version of the same c++ class:

      Connections{
            target: x
           function onCreateObject ()
                    {
                        const component = Qt.createComponent("x.qml")
                        if (component.status === Component.Ready)
                           object = component.createObject(window)
                        else
                            console.log(component.errorString())
                    }
        }
    

    Using a variant of this code, I can spawn as many qml objects as I desire, but I'm unsure how to create and connect each one to their own cpp object of the same class.

    If I spawn
    qmlObj1 it should be pair with c++backend1
    qmlObj2 it should be pair with c++backend2

    and so on...

    How can I connect dynamically created qml objects to their own backend class?

    J 1 Reply Last reply 5 days ago
    0
    • J Jay_emissary
      4 days ago

      @Bob64 Oh, whoops! I must have overlooked that one. Thanks for catching that, lol... Now the QML objects are on the screen and the C++ objects get created as well!

      The only issue I have at this point is that I'm not so sure that the C++ object is associated with the QML objects. I added this statement to the HitObject's constructor:

          qDebug() <<property("x").toDouble();
      

      And because I set the x to 100 using in the following code, I should expect to receive that value when the c++ object is created.

      
          Repeater{
              model: hitObjectModel
              delegate:  Rectangle {
                      id: image      
                      width: 10
                      height: 40
                      color: "white"
                      x: 100
                      y:100}
          }
      

      But instead, I'm getting a 0. Could this possibly be because the QML is only reacting to the fact my object list has increased, and less so the fact that a C++ object has been created to pair with the corresponding QML object?

      B Offline
      B Offline
      Bob64
      wrote 4 days ago last edited by
      #22

      @Jay_emissary @Jay_emissary There is no implicit association of the C++ object with the QML object. Each object in your "view" is associated with a known index into the model and can access whatever "data" the model exposes at that index. In your case I believe you are exposing a whole object as your data, but often the underlying items in a model are more encapsulated and you just expose certain named fields at each index.

      Essentially there is a one way data flow from the model to the view. This doesn't mean that you can't expose functions from your model that can be used to update it. This would have to follow a strict process of updating the model items and providing appropriate signals to notify the view to update itself from the model.

      One simple thing that is worth asking: would it make sense for the X and Y positions to be define by properties of your model object?

      Otherwise, maybe it would help if you had another go at outlining what you are trying to achieve. For example, even if you don't know exactly how to write it, what is that you want to achieve in the QML layer and how will it relate to the C++ objects in the backend?

      J 1 Reply Last reply 3 days ago
      1
      • J Jay_emissary
        6 days ago

        Greetings,
        I'm trying to dynamically create qml objects that should be paired with a corresponding version of the same c++ class:

          Connections{
                target: x
               function onCreateObject ()
                        {
                            const component = Qt.createComponent("x.qml")
                            if (component.status === Component.Ready)
                               object = component.createObject(window)
                            else
                                console.log(component.errorString())
                        }
            }
        

        Using a variant of this code, I can spawn as many qml objects as I desire, but I'm unsure how to create and connect each one to their own cpp object of the same class.

        If I spawn
        qmlObj1 it should be pair with c++backend1
        qmlObj2 it should be pair with c++backend2

        and so on...

        How can I connect dynamically created qml objects to their own backend class?

        J Offline
        J Offline
        JKSH
        Moderators
        wrote 5 days ago last edited by JKSH
        #2

        @Jay_emissary said in How to dynamically pair qml objects with c++ objects:

        How can I connect dynamically created qml objects to their own backend class?

        Instead of having separate "QML object" and "C++ backend object", combine them into a single C++ class. Add the QML_ELEMENT macro and you'll be able to instantiate that C++ object directly in QML: https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#registering-an-instantiable-object-type

        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

        1 Reply Last reply
        0
        • J JKSH referenced this topic 5 days ago
        • J Offline
          J Offline
          Jay_emissary
          wrote 5 days ago last edited by
          #3

          I see... following your advice, while I can handle dynamically creating the C++ objects, I'm quite unfamiliar with the syntax for setting everything up in QML. This might just be a conceptual struggle for me, so please excuse my ignorance.

          I can spawn instances of the backend, but how does QML know to have a GUI ready to pair with each instance? To keep my logic flexible, I need to avoid hardcoding objects at all costs, no? The documentation appears to be suggesting hard-coding a QML object, which I can't afford since I will be spawning many of the same objects.

          image.png

          1 Reply Last reply
          0
          • B Offline
            B Offline
            Bob64
            wrote 5 days ago last edited by Bob64
            #4

            I don't know if I am 100% sure what you want to do, but what I can gather is the following. Please forgive me if I have got this wrong.

            • A C++ backend object
            • A QML visual object that exists in a 1-1 relationship with the C++ object
            • Many such objects created dynamically

            One possible approach which I think you have already seen is to create a C++ object that is instantiable in QML. If you have this then you can define a QML object that contains that object, which adds the visual/UI aspects but uses the contained object for its implementation.

            So you would have something like this in a file MyObject.qml

            Item { // or whatever
                MyObjectImpl { // instantiate the object exposed from C++
                    id: impl
                }
                ...
                // implement visual content MyObject making use of properties, signals, functions, etc., available from MyObjectImpl
                ...
            }
            

            Once this is defined, you can create multiple instances of MyObject dynamically using createComponent/createObject or maybe using a model-repeater approach if that makes sense for your use case.

            J 1 Reply Last reply 5 days ago
            0
            • J Offline
              J Offline
              JKSH
              Moderators
              wrote 5 days ago last edited by
              #5

              My understanding is the same as @Bob64's, and I think his suggestions are sound

              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

              1 Reply Last reply
              0
              • B Bob64
                5 days ago

                I don't know if I am 100% sure what you want to do, but what I can gather is the following. Please forgive me if I have got this wrong.

                • A C++ backend object
                • A QML visual object that exists in a 1-1 relationship with the C++ object
                • Many such objects created dynamically

                One possible approach which I think you have already seen is to create a C++ object that is instantiable in QML. If you have this then you can define a QML object that contains that object, which adds the visual/UI aspects but uses the contained object for its implementation.

                So you would have something like this in a file MyObject.qml

                Item { // or whatever
                    MyObjectImpl { // instantiate the object exposed from C++
                        id: impl
                    }
                    ...
                    // implement visual content MyObject making use of properties, signals, functions, etc., available from MyObjectImpl
                    ...
                }
                

                Once this is defined, you can create multiple instances of MyObject dynamically using createComponent/createObject or maybe using a model-repeater approach if that makes sense for your use case.

                J Offline
                J Offline
                Jay_emissary
                wrote 5 days ago last edited by Jay_emissary
                #6

                @Bob64 Hello, I truly appreciate your in-depth explanation on creating dynamic objects in QML. Yes, I'm aware of this approach to creating dynamic QML objects with C++ implementation, but I'm not sure if that would work in my case (unless I'm missing something here.) I'm so sorry for all the confusion, so let me go in-depth regarding my process:

                I'm using my GameManager class in C++ to spawn "hitobjects." I would like to spawn these repeatedly, which is cued by a timer, so I have a function that I can call when it's time to create the objects. Because I wasn't sure if I should be using QML or C++ to create the object, I have two approaches here:

                1. Signal to create the object in qml
                void GameManager::spawnNote(int index)
                {
                    emit createHitObject();
                
                }
                

                OR 2. Create an instance of the object in C++

                void GameManager::spawnNote(int index)
                {
                    new HitObject(this);
                
                }
                

                If I use method 1. I'll be spawning the objects in QML:

                    Connections{
                        target: gameManager
                       function onCreateHitObject ()
                                {
                                    const component = Qt.createComponent("HitObject.qml")
                                    if (component.status === Component.Ready)
                                        hitObject = component.createObject(window)
                                    else
                                        console.log(component.errorString())
                                }
                    }
                

                This successfully puts the object on the screen, but we should note that I did not create a c++ instance to pair with said object. This means I'll need to create one (?) How would I hook it up to this newly-created QML object?

                If we went with the method 2. I'm creating a c++ object, but we should remember that no qml object is created to pair with it. So I would need to create one, but how to parent it to this newly created c++ object (?)

                But let's also discuss your approach to the problem

                J 1 Reply Last reply 5 days ago
                0
                • J Jay_emissary
                  5 days ago

                  @Bob64 Hello, I truly appreciate your in-depth explanation on creating dynamic objects in QML. Yes, I'm aware of this approach to creating dynamic QML objects with C++ implementation, but I'm not sure if that would work in my case (unless I'm missing something here.) I'm so sorry for all the confusion, so let me go in-depth regarding my process:

                  I'm using my GameManager class in C++ to spawn "hitobjects." I would like to spawn these repeatedly, which is cued by a timer, so I have a function that I can call when it's time to create the objects. Because I wasn't sure if I should be using QML or C++ to create the object, I have two approaches here:

                  1. Signal to create the object in qml
                  void GameManager::spawnNote(int index)
                  {
                      emit createHitObject();
                  
                  }
                  

                  OR 2. Create an instance of the object in C++

                  void GameManager::spawnNote(int index)
                  {
                      new HitObject(this);
                  
                  }
                  

                  If I use method 1. I'll be spawning the objects in QML:

                      Connections{
                          target: gameManager
                         function onCreateHitObject ()
                                  {
                                      const component = Qt.createComponent("HitObject.qml")
                                      if (component.status === Component.Ready)
                                          hitObject = component.createObject(window)
                                      else
                                          console.log(component.errorString())
                                  }
                      }
                  

                  This successfully puts the object on the screen, but we should note that I did not create a c++ instance to pair with said object. This means I'll need to create one (?) How would I hook it up to this newly-created QML object?

                  If we went with the method 2. I'm creating a c++ object, but we should remember that no qml object is created to pair with it. So I would need to create one, but how to parent it to this newly created c++ object (?)

                  But let's also discuss your approach to the problem

                  J Offline
                  J Offline
                  Jay_emissary
                  wrote 5 days ago last edited by Jay_emissary
                  #7

                  @Jay_emissary

                  If I understand correctly, I'm placing registered C++ code into QML
                  1c9bf43c-7e19-4512-8465-9cb4621f6aab-image.png

                  This is from the qml file for hitObject (it serves as the blueprint for every object I'm creating dynamically):
                  2ac9cd6b-bfb0-4227-8e85-3809265511d7-image.png

                  As you can see, I'm setting up that c++ object here. And because I'm placing the backend in the QML file, I'll be using approach 1 from the previous reply (emit a signal to create the QML object)

                  This causes a crash with no explanation in the application output. Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object? I would prefer to, so I can verify that the backend is up and running.

                  HitObject::HitObject(QObject *parent)
                  {
                      connect(Timer, &TimeStep::Tick, this, &HitObject::Tick);
                      qDebug() <<"Spawned";
                  }
                  

                  I hope this explanation clears things up. Please feel free to let me know if there are any misconceptions.

                  B J 2 Replies Last reply 5 days ago
                  0
                  • J Jay_emissary
                    5 days ago

                    @Jay_emissary

                    If I understand correctly, I'm placing registered C++ code into QML
                    1c9bf43c-7e19-4512-8465-9cb4621f6aab-image.png

                    This is from the qml file for hitObject (it serves as the blueprint for every object I'm creating dynamically):
                    2ac9cd6b-bfb0-4227-8e85-3809265511d7-image.png

                    As you can see, I'm setting up that c++ object here. And because I'm placing the backend in the QML file, I'll be using approach 1 from the previous reply (emit a signal to create the QML object)

                    This causes a crash with no explanation in the application output. Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object? I would prefer to, so I can verify that the backend is up and running.

                    HitObject::HitObject(QObject *parent)
                    {
                        connect(Timer, &TimeStep::Tick, this, &HitObject::Tick);
                        qDebug() <<"Spawned";
                    }
                    

                    I hope this explanation clears things up. Please feel free to let me know if there are any misconceptions.

                    B Offline
                    B Offline
                    Bob64
                    wrote 5 days ago last edited by
                    #8

                    @Jay_emissary what you are showing here, with the HitObjectBackend is how I was imagining it.

                    Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object?

                    Yes, you should see this. As a very quick thing to try I would move the debug to be the first statement in the constructor body, just in case the connect is causing the crash for some reason.

                    Anyway, in principle this should work. Have you tried anything to try to debug your code? For example, have you tried attaching a debugger? I use Qt Creator and sometimes find that, if I start the program under the debugger I am more successful in seeing what has happened than if I start it not under the debugger and wait for the crash and then try to attach.

                    J 2 Replies Last reply 5 days ago
                    1
                    • B Bob64
                      5 days ago

                      @Jay_emissary what you are showing here, with the HitObjectBackend is how I was imagining it.

                      Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object?

                      Yes, you should see this. As a very quick thing to try I would move the debug to be the first statement in the constructor body, just in case the connect is causing the crash for some reason.

                      Anyway, in principle this should work. Have you tried anything to try to debug your code? For example, have you tried attaching a debugger? I use Qt Creator and sometimes find that, if I start the program under the debugger I am more successful in seeing what has happened than if I start it not under the debugger and wait for the crash and then try to attach.

                      J Offline
                      J Offline
                      Jay_emissary
                      wrote 5 days ago last edited by
                      #9

                      @Bob64

                      @Bob64 said in How to dynamically pair qml objects with c++ objects:

                      Yes, you should see this. As a very quick thing to try I would move the debug to be the first statement in the constructor body, just in case the connect is causing the crash for some reason.

                      This actually worked!!! I didn't know connect could cause ambiguous crashes like the one I was experiencing. I'll be sure to verify my references. I do use the debugger, actually! In this case, it didn't cross my mind to try, haha. I just assumed I was setting up the QML file incorrectly.

                      That said, I'd like to thank you and JKSH for the help. Qt is occasionally challenging to adapt to, but I'm learning a lot creating these projects!

                      1 Reply Last reply
                      0
                      • J Jay_emissary has marked this topic as solved 5 days ago
                      • B Bob64
                        5 days ago

                        @Jay_emissary what you are showing here, with the HitObjectBackend is how I was imagining it.

                        Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object?

                        Yes, you should see this. As a very quick thing to try I would move the debug to be the first statement in the constructor body, just in case the connect is causing the crash for some reason.

                        Anyway, in principle this should work. Have you tried anything to try to debug your code? For example, have you tried attaching a debugger? I use Qt Creator and sometimes find that, if I start the program under the debugger I am more successful in seeing what has happened than if I start it not under the debugger and wait for the crash and then try to attach.

                        J Offline
                        J Offline
                        Jay_emissary
                        wrote 5 days ago last edited by
                        #10

                        @Bob64 Oh, I have one, quick question if you don't mind: how can I pass any arguments the c++ object's constructor? This is what I suspect caused the crash: the constructor gets called as QML creates the c++ instance, but I never passed in any arguments, leaving any parameters (GameInitializer* init) as null.

                        HitObject::HitObject(QObject *parent,GameInitializer* init)
                        {
                            qDebug() <<"Spawned";
                            connect(init->deltaTimer, &TimeStep::Tick, this, &HitObject::Tick);
                        }
                        

                        That said, connect gets called with a nullptr, and the game crashes. How can I make sure each C++ instance gets a pointer argument passed in? Or is this not possible using the QML->C++ method? I think I have some workarounds...

                        B 1 Reply Last reply 5 days ago
                        0
                        • GrecKoG Offline
                          GrecKoG Offline
                          GrecKo
                          Qt Champions 2018
                          wrote 5 days ago last edited by
                          #11

                          Use the model/view paradigm. Your backend shouldn't be aware of your QML code.

                          In your spawnNote create a new object and add it to a model.
                          In QML use a Repeater if you need a visual representation of your backend object. You can then bind to your object with one of the roles you exposed in your model.

                          You don't need to instantiate a backend object in QML.

                          J 1 Reply Last reply 4 days ago
                          4
                          • J Jay_emissary
                            5 days ago

                            @Bob64 Oh, I have one, quick question if you don't mind: how can I pass any arguments the c++ object's constructor? This is what I suspect caused the crash: the constructor gets called as QML creates the c++ instance, but I never passed in any arguments, leaving any parameters (GameInitializer* init) as null.

                            HitObject::HitObject(QObject *parent,GameInitializer* init)
                            {
                                qDebug() <<"Spawned";
                                connect(init->deltaTimer, &TimeStep::Tick, this, &HitObject::Tick);
                            }
                            

                            That said, connect gets called with a nullptr, and the game crashes. How can I make sure each C++ instance gets a pointer argument passed in? Or is this not possible using the QML->C++ method? I think I have some workarounds...

                            B Offline
                            B Offline
                            Bob64
                            wrote 5 days ago last edited by
                            #12

                            @Jay_emissary What Grecko is suggesting is what I originally had in mind when I first answered your other thread. There are various ways to do things in QML when it comes to exposing C++ functionality, and which is the best approach can depend on the details. In a larger application you will often end up using a variety of different approaches to fit different needs. The "C++ object instantiable as a QML object" is a useful approach to have in your toolbox, but the constructor argument issue adds a complication. The model-repeater approach gives you more control over the construction of the backend objects. The key thing is whether you can see a way to incorporate a Repeater into your QML. If you can do this, it honestly does simplify and clean things up because all the dynamic construction of QML objects is taken care of.

                            J 1 Reply Last reply 4 days ago
                            1
                            • J Jay_emissary
                              5 days ago

                              @Jay_emissary

                              If I understand correctly, I'm placing registered C++ code into QML
                              1c9bf43c-7e19-4512-8465-9cb4621f6aab-image.png

                              This is from the qml file for hitObject (it serves as the blueprint for every object I'm creating dynamically):
                              2ac9cd6b-bfb0-4227-8e85-3809265511d7-image.png

                              As you can see, I'm setting up that c++ object here. And because I'm placing the backend in the QML file, I'll be using approach 1 from the previous reply (emit a signal to create the QML object)

                              This causes a crash with no explanation in the application output. Say the code did work, should I expect to receive the message from HitObject's cpp constructor, for every created QML object? I would prefer to, so I can verify that the backend is up and running.

                              HitObject::HitObject(QObject *parent)
                              {
                                  connect(Timer, &TimeStep::Tick, this, &HitObject::Tick);
                                  qDebug() <<"Spawned";
                              }
                              

                              I hope this explanation clears things up. Please feel free to let me know if there are any misconceptions.

                              J Offline
                              J Offline
                              JKSH
                              Moderators
                              wrote 4 days ago last edited by
                              #13

                              @Jay_emissary I'm glad to hear that you've made good progress!

                              I have another suggestion: Do not call qmlRegister*() functions to register your QML type at runtime. Instead, use the QML_ELEMENT macro to register your QML type at compile-time -- see https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#registering-an-instantiable-object-type

                              I didn't know connect could cause ambiguous crashes like the one I was experiencing.

                              The connect() function didn't cause the crash. Dereferencing an invalid pointer caused the crash.

                              how can I pass any arguments the c++ object's constructor?

                              You cannot (at least not with current versions of Qt). QML-instantiable QObjects need to be default-constructible, which means you need to allow this to be called in C++: auto obj = new HitObject;

                              With the example code that you gave, you can remove the GameInitializer* parameter from your constructor. Let the code that creates your HitObject also connect TimeStep::Tick() to HitObject::Tick().

                              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                              1 Reply Last reply
                              3
                              • GrecKoG GrecKo
                                5 days ago

                                Use the model/view paradigm. Your backend shouldn't be aware of your QML code.

                                In your spawnNote create a new object and add it to a model.
                                In QML use a Repeater if you need a visual representation of your backend object. You can then bind to your object with one of the roles you exposed in your model.

                                You don't need to instantiate a backend object in QML.

                                J Offline
                                J Offline
                                Jay_emissary
                                wrote 4 days ago last edited by
                                #14

                                @GrecKo Good evening,
                                I've spent hours today researching and trying to implement the model system into my project. I did run into a couple of issues with this "simple" approach, though. Here's what I've done:

                                I use this function to start the object creation process

                                void GameManager::spawnNote(int index)
                                {
                                    emit createHitObject();
                                }
                                

                                In main.qml I instantiate the C++ AbstractListModel and call the C++ function, createHitObject() to spawn the hitObjects.

                                    HitObjectModel{
                                        id:hitObjModel
                                    }
                                
                                    Repeater{
                                        model: hitObjModel
                                        delegate:  Rectangle {
                                                id: image      
                                                width: 10
                                                height: 40
                                                color: "white"
                                                x: 100
                                                y:100}
                                    }
                                
                                    Connections{
                                        target: gameManager
                                       function onCreateHitObject ()
                                                {
                                                    hitObjModel.createHitObject()
                                                }
                                    }
                                

                                Now let's take a look at hitObjModel.createHitObject() from c++'s side:

                                void HitObjectModel::createHitObject()
                                {
                                    beginInsertRows(QModelIndex(),objects.size(),objects.size());
                                    objects.append(new HitObject());
                                    endInsertRows();
                                
                                }
                                

                                I use this code to ensure that the repeater spawns enough visual elements to pair with each HitObject. This successfully puts the rectangles on the screen, and I can control each of their functions from c++.

                                J 1 Reply Last reply 4 days ago
                                0
                                • J Jay_emissary
                                  4 days ago

                                  @GrecKo Good evening,
                                  I've spent hours today researching and trying to implement the model system into my project. I did run into a couple of issues with this "simple" approach, though. Here's what I've done:

                                  I use this function to start the object creation process

                                  void GameManager::spawnNote(int index)
                                  {
                                      emit createHitObject();
                                  }
                                  

                                  In main.qml I instantiate the C++ AbstractListModel and call the C++ function, createHitObject() to spawn the hitObjects.

                                      HitObjectModel{
                                          id:hitObjModel
                                      }
                                  
                                      Repeater{
                                          model: hitObjModel
                                          delegate:  Rectangle {
                                                  id: image      
                                                  width: 10
                                                  height: 40
                                                  color: "white"
                                                  x: 100
                                                  y:100}
                                      }
                                  
                                      Connections{
                                          target: gameManager
                                         function onCreateHitObject ()
                                                  {
                                                      hitObjModel.createHitObject()
                                                  }
                                      }
                                  

                                  Now let's take a look at hitObjModel.createHitObject() from c++'s side:

                                  void HitObjectModel::createHitObject()
                                  {
                                      beginInsertRows(QModelIndex(),objects.size(),objects.size());
                                      objects.append(new HitObject());
                                      endInsertRows();
                                  
                                  }
                                  

                                  I use this code to ensure that the repeater spawns enough visual elements to pair with each HitObject. This successfully puts the rectangles on the screen, and I can control each of their functions from c++.

                                  J Offline
                                  J Offline
                                  Jay_emissary
                                  wrote 4 days ago last edited by
                                  #15

                                  @Jay_emissary Here's where the complexity comes in:
                                  I need to reference deltatimer, a QTimer that's instantiated from another class. Each object should have this connect function attached, so it fires the tick function for each corresponding object. Essentially, this code:

                                  • HitObjectModel.cpp
                                     HitObject* hitObj = new HitObject();
                                      beginInsertRows(QModelIndex(),objects.size(),objects.size());
                                      objects.append(hitObj);
                                      endInsertRows();
                                      connect(deltaTimer, &TimeStep::Tick,hitObj, &HitObject::Tick);
                                  

                                  The only way to access a C++ object created by another class is by passing it into the model, but since the model is created from QML, there is no way for it to access deltatimer from the "initializer" class.

                                  My hope is that I can create the model in C++ instead and expose it to QML. That way, I can pass in the timer reference and use it across all the created objects.

                                  This is from the initializer class:

                                      deltaTimer = new TimeStep();
                                      hitModelObj = new HitObjectModel(this,deltaTimer);
                                      engine->rootContext()->setContextProperty("HitObjectModel", hitModelObj);
                                  

                                  Now I have the deltaTimer reference. I should be able to access the model in QML too, no?

                                  I'll also call createHitObject() from the model directly from the spawnNote function instead of emitting a signal like earlier

                                  void GameManager::spawnNote(int index)
                                  {
                                      hitObjectModel->createHitObject();
                                  

                                  in QML all I should need is a reference to the c++ model, which should be exposed now right?

                                  Repeater{
                                          model: hitObjModel
                                           delegate:  Rectangle {
                                                          id: image      
                                                          width: 10
                                                          height: 40
                                                          color: "white"
                                                          x: 100
                                                          y:100}
                                              }
                                  

                                  For some reason, Qt throws me an error: Main.qml:25: ReferenceError: hitObjModel is not defined

                                  How doesn't Qt recognize the model after it's created??

                                  Is what I'm trying to do impossible to execute in Qt? I'm at a loss...

                                  B 1 Reply Last reply 4 days ago
                                  0
                                  • B Bob64
                                    5 days ago

                                    @Jay_emissary What Grecko is suggesting is what I originally had in mind when I first answered your other thread. There are various ways to do things in QML when it comes to exposing C++ functionality, and which is the best approach can depend on the details. In a larger application you will often end up using a variety of different approaches to fit different needs. The "C++ object instantiable as a QML object" is a useful approach to have in your toolbox, but the constructor argument issue adds a complication. The model-repeater approach gives you more control over the construction of the backend objects. The key thing is whether you can see a way to incorporate a Repeater into your QML. If you can do this, it honestly does simplify and clean things up because all the dynamic construction of QML objects is taken care of.

                                    J Offline
                                    J Offline
                                    Jay_emissary
                                    wrote 4 days ago last edited by
                                    #16

                                    @Bob64 Gotcha! I'll be sure to take note of this whenever I'm deciding on how I might approach connecting C++ to QML in my projects.

                                    1 Reply Last reply
                                    0
                                    • J Jay_emissary
                                      4 days ago

                                      @Jay_emissary Here's where the complexity comes in:
                                      I need to reference deltatimer, a QTimer that's instantiated from another class. Each object should have this connect function attached, so it fires the tick function for each corresponding object. Essentially, this code:

                                      • HitObjectModel.cpp
                                         HitObject* hitObj = new HitObject();
                                          beginInsertRows(QModelIndex(),objects.size(),objects.size());
                                          objects.append(hitObj);
                                          endInsertRows();
                                          connect(deltaTimer, &TimeStep::Tick,hitObj, &HitObject::Tick);
                                      

                                      The only way to access a C++ object created by another class is by passing it into the model, but since the model is created from QML, there is no way for it to access deltatimer from the "initializer" class.

                                      My hope is that I can create the model in C++ instead and expose it to QML. That way, I can pass in the timer reference and use it across all the created objects.

                                      This is from the initializer class:

                                          deltaTimer = new TimeStep();
                                          hitModelObj = new HitObjectModel(this,deltaTimer);
                                          engine->rootContext()->setContextProperty("HitObjectModel", hitModelObj);
                                      

                                      Now I have the deltaTimer reference. I should be able to access the model in QML too, no?

                                      I'll also call createHitObject() from the model directly from the spawnNote function instead of emitting a signal like earlier

                                      void GameManager::spawnNote(int index)
                                      {
                                          hitObjectModel->createHitObject();
                                      

                                      in QML all I should need is a reference to the c++ model, which should be exposed now right?

                                      Repeater{
                                              model: hitObjModel
                                               delegate:  Rectangle {
                                                              id: image      
                                                              width: 10
                                                              height: 40
                                                              color: "white"
                                                              x: 100
                                                              y:100}
                                                  }
                                      

                                      For some reason, Qt throws me an error: Main.qml:25: ReferenceError: hitObjModel is not defined

                                      How doesn't Qt recognize the model after it's created??

                                      Is what I'm trying to do impossible to execute in Qt? I'm at a loss...

                                      B Offline
                                      B Offline
                                      Bob64
                                      wrote 4 days ago last edited by
                                      #17

                                      @Jay_emissary said in How to dynamically pair qml objects with c++ objects:

                                      "HitObjectModel"

                                      This is the exact name you should use in QML, not hitObjectModel.

                                      J 1 Reply Last reply 4 days ago
                                      1
                                      • B Bob64
                                        4 days ago

                                        @Jay_emissary said in How to dynamically pair qml objects with c++ objects:

                                        "HitObjectModel"

                                        This is the exact name you should use in QML, not hitObjectModel.

                                        J Offline
                                        J Offline
                                        Jay_emissary
                                        wrote 4 days ago last edited by
                                        #18

                                        @Bob64 Oh, whoops! I must have overlooked that one. Thanks for catching that, lol... Now the QML objects are on the screen and the C++ objects get created as well!

                                        The only issue I have at this point is that I'm not so sure that the C++ object is associated with the QML objects. I added this statement to the HitObject's constructor:

                                            qDebug() <<property("x").toDouble();
                                        

                                        And because I set the x to 100 using in the following code, I should expect to receive that value when the c++ object is created.

                                        
                                            Repeater{
                                                model: hitObjectModel
                                                delegate:  Rectangle {
                                                        id: image      
                                                        width: 10
                                                        height: 40
                                                        color: "white"
                                                        x: 100
                                                        y:100}
                                            }
                                        

                                        But instead, I'm getting a 0. Could this possibly be because the QML is only reacting to the fact my object list has increased, and less so the fact that a C++ object has been created to pair with the corresponding QML object?

                                        jsulmJ B 2 Replies Last reply 4 days ago
                                        0
                                        • J Jay_emissary
                                          4 days ago

                                          @Bob64 Oh, whoops! I must have overlooked that one. Thanks for catching that, lol... Now the QML objects are on the screen and the C++ objects get created as well!

                                          The only issue I have at this point is that I'm not so sure that the C++ object is associated with the QML objects. I added this statement to the HitObject's constructor:

                                              qDebug() <<property("x").toDouble();
                                          

                                          And because I set the x to 100 using in the following code, I should expect to receive that value when the c++ object is created.

                                          
                                              Repeater{
                                                  model: hitObjectModel
                                                  delegate:  Rectangle {
                                                          id: image      
                                                          width: 10
                                                          height: 40
                                                          color: "white"
                                                          x: 100
                                                          y:100}
                                              }
                                          

                                          But instead, I'm getting a 0. Could this possibly be because the QML is only reacting to the fact my object list has increased, and less so the fact that a C++ object has been created to pair with the corresponding QML object?

                                          jsulmJ Offline
                                          jsulmJ Offline
                                          jsulm
                                          Lifetime Qt Champion
                                          wrote 4 days ago last edited by
                                          #19

                                          @Jay_emissary said in How to dynamically pair qml objects with c++ objects:

                                          But instead, I'm getting a 0

                                          I'm not a QML expert, but maybe QML uses setters to set members like x?

                                          https://forum.qt.io/topic/113070/qt-code-of-conduct

                                          J 1 Reply Last reply 4 days ago
                                          0
                                          • jsulmJ jsulm
                                            4 days ago

                                            @Jay_emissary said in How to dynamically pair qml objects with c++ objects:

                                            But instead, I'm getting a 0

                                            I'm not a QML expert, but maybe QML uses setters to set members like x?

                                            J Offline
                                            J Offline
                                            Jay_emissary
                                            wrote 4 days ago last edited by
                                            #20

                                            @jsulm As far as I know, yeah, you should be able to call a setProperty function in C++, and in QML you can directly set properties like x as well. Though, I'm currently trying to get x so I can verify that the c++ object is hooked up and can read QML's properties. It's important for me to get and set x and y properties so that I can perform functions such as smoothly moving objects across the screen at a framerate-dependent speed.

                                            jsulmJ 1 Reply Last reply 4 days ago
                                            0

                                            1/29

                                            15 Jun 2025, 10:42

                                            • Login

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