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. Is it possible to pass an instance of a derived `QAbstractListModel` from backend to QML without using `setContextProperty`?
QtWS25 Last Chance

Is it possible to pass an instance of a derived `QAbstractListModel` from backend to QML without using `setContextProperty`?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
9 Posts 3 Posters 303 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.
  • C Offline
    C Offline
    Curtwagner1984
    wrote on last edited by
    #1

    Hello,

    I'm trying to figure out how to pass an instance of a model to QML from the backend, but I don't want to use setContextProperty to expose said model.
    Because I want to dynamically change the model the view is using.

    I know that I can register the model as a QML type and then instantiate it on the QML side, but doing this will lock me out of changing the model data from the backend,
    because as far as I know, the backend doesn't have references to QML instantiated classes.

    I tried registering QAbstractListModel as a QML type and then pass it as a return value of a slot, like so:

        @Slot(result=VideoModel)
        def get_video_model(self):
            return self.video_model
    

    And in QML

        Shortcut {
            id: getModelShortuct
            sequences: ["Ctrl+W"]
            onActivated: {
                console.log("getModelShortuct activated")
                console.log("bridge.get_video_model()= " + bridge.get_video_model())
            }
        }
    

    Where bridge is the class that's exposed through setContextProperty .
    When trying this, I get "Error: Unknown method return type: QAbstractListModel* ". This also happens when registering the video model class specifically as a QML type, not just QAbstractListModel

    Alternatively, I wonder if it's possible to expose a class through setContextProperty and have one of its class variables be a model and then change the value of the said class variable. For example

    class ModelWrapper(QObject):
    
        def __init__(self):
        super().__init__()
        self.model = SomeModel()
    
        def switch_model(self):
            self.model = AnotherModel()
    
    

    And in QML:

    GridView{
        id:myGridview
        model:ModelWrapper.model
    }
    
    Button{
        id:modelSwitchButton
        onClicked{
            ModelWrapper.switch_model()
        }
    }
    
    raven-worxR 1 Reply Last reply
    0
    • C Offline
      C Offline
      Curtwagner1984
      wrote on last edited by
      #4

      So, answering my own question:

      Do you mean like it's described here?

      Yes, it is indeed how it's described here.

      Also, do SomeModel and AnotherModel needs to be registered as a QML type, or is it enough to register QAbstractListModel if both of them derive from it?

      No. Apparently, you need to specify that the 'return' type is just a QObject neither QAbstractListModel nor its derived classes need to be registered.


      This is what I ended up doing to test this:

      
      class CurrentView(QObject):
      
          def __init__(self):
              super().__init__()
              self.person_model: PersonModel = PersonModel()
              self.video_model: VideoModel = VideoModel()
              self.search_backend: SearchBackend = SearchBackend(self.person_model, self.video_model)
              self._current_model = self.person_model # setting current model to this for test
              self.search_backend.video_search("", "Name", False) #fills models with data
      
          def _current_model(self):
              return self._current_model
      
          @Signal
          def current_model_changed(self):
              pass
      
          @Slot()
          def swap_model(self): #called from QML
              logger.info(f"Swapping Model...")
              if self._current_model == self.video_model:
                  self._current_model = self.person_model
              else:
                  self._current_model = self.video_model
              self.current_model_changed.emit()
      
          #the return type needs to be QObject.
          #At first I tried QAbstractListModel or it's derived classes. Didn't work.
          current_model = Property(QObject, _current_model, notify=current_model_changed) 
      
      

      In QML:

      Shortcut {
          id: swapModels
          sequences: ["Ctrl+W"]
          onActivated: {
              console.log("Swapping Models...")
              current_view.swap_model()
          }
      }
      
      GridView {
          id: gridview
          anchors.fill: parent
          model: current_view.current_model
          delegate: MyDelegate{}
      
      }
      

      CurrentView is exposed through:

          cw = CurrentView()
          engine.rootContext().setContextProperty("current_view", cw)
      

      It works like a charm, when I press Ctrl+W the model instantly switches.

      This SO answer helped me figure out the missing pieces. Thank you @raven-worx for pointing me in the right direction.

      1 Reply Last reply
      0
      • C Curtwagner1984

        Hello,

        I'm trying to figure out how to pass an instance of a model to QML from the backend, but I don't want to use setContextProperty to expose said model.
        Because I want to dynamically change the model the view is using.

        I know that I can register the model as a QML type and then instantiate it on the QML side, but doing this will lock me out of changing the model data from the backend,
        because as far as I know, the backend doesn't have references to QML instantiated classes.

        I tried registering QAbstractListModel as a QML type and then pass it as a return value of a slot, like so:

            @Slot(result=VideoModel)
            def get_video_model(self):
                return self.video_model
        

        And in QML

            Shortcut {
                id: getModelShortuct
                sequences: ["Ctrl+W"]
                onActivated: {
                    console.log("getModelShortuct activated")
                    console.log("bridge.get_video_model()= " + bridge.get_video_model())
                }
            }
        

        Where bridge is the class that's exposed through setContextProperty .
        When trying this, I get "Error: Unknown method return type: QAbstractListModel* ". This also happens when registering the video model class specifically as a QML type, not just QAbstractListModel

        Alternatively, I wonder if it's possible to expose a class through setContextProperty and have one of its class variables be a model and then change the value of the said class variable. For example

        class ModelWrapper(QObject):
        
            def __init__(self):
            super().__init__()
            self.model = SomeModel()
        
            def switch_model(self):
                self.model = AnotherModel()
        
        

        And in QML:

        GridView{
            id:myGridview
            model:ModelWrapper.model
        }
        
        Button{
            id:modelSwitchButton
            onClicked{
                ModelWrapper.switch_model()
            }
        }
        
        raven-worxR Offline
        raven-worxR Offline
        raven-worx
        Moderators
        wrote on last edited by
        #2

        @Curtwagner1984
        sure, if ModelWrapper.model is a property with a notifier signal

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        1 Reply Last reply
        2
        • C Offline
          C Offline
          Curtwagner1984
          wrote on last edited by
          #3

          Thank you for the reply.

          Do you mean like it's described here?

          Also, do SomeModel and AnotherModel needs to be registered as a QML type, or is it enough to register QAbstractListModel if both of them derive from it?

          1 Reply Last reply
          0
          • C Offline
            C Offline
            Curtwagner1984
            wrote on last edited by
            #4

            So, answering my own question:

            Do you mean like it's described here?

            Yes, it is indeed how it's described here.

            Also, do SomeModel and AnotherModel needs to be registered as a QML type, or is it enough to register QAbstractListModel if both of them derive from it?

            No. Apparently, you need to specify that the 'return' type is just a QObject neither QAbstractListModel nor its derived classes need to be registered.


            This is what I ended up doing to test this:

            
            class CurrentView(QObject):
            
                def __init__(self):
                    super().__init__()
                    self.person_model: PersonModel = PersonModel()
                    self.video_model: VideoModel = VideoModel()
                    self.search_backend: SearchBackend = SearchBackend(self.person_model, self.video_model)
                    self._current_model = self.person_model # setting current model to this for test
                    self.search_backend.video_search("", "Name", False) #fills models with data
            
                def _current_model(self):
                    return self._current_model
            
                @Signal
                def current_model_changed(self):
                    pass
            
                @Slot()
                def swap_model(self): #called from QML
                    logger.info(f"Swapping Model...")
                    if self._current_model == self.video_model:
                        self._current_model = self.person_model
                    else:
                        self._current_model = self.video_model
                    self.current_model_changed.emit()
            
                #the return type needs to be QObject.
                #At first I tried QAbstractListModel or it's derived classes. Didn't work.
                current_model = Property(QObject, _current_model, notify=current_model_changed) 
            
            

            In QML:

            Shortcut {
                id: swapModels
                sequences: ["Ctrl+W"]
                onActivated: {
                    console.log("Swapping Models...")
                    current_view.swap_model()
                }
            }
            
            GridView {
                id: gridview
                anchors.fill: parent
                model: current_view.current_model
                delegate: MyDelegate{}
            
            }
            

            CurrentView is exposed through:

                cw = CurrentView()
                engine.rootContext().setContextProperty("current_view", cw)
            

            It works like a charm, when I press Ctrl+W the model instantly switches.

            This SO answer helped me figure out the missing pieces. Thank you @raven-worx for pointing me in the right direction.

            1 Reply Last reply
            0
            • GrecKoG Offline
              GrecKoG Offline
              GrecKo
              Qt Champions 2018
              wrote on last edited by
              #5

              QAbstractListModel as a property type or a return type should work, using QObject instead is not the correct solution.
              Have you tried calling qRegisterMetaType?

              raven-worxR C 2 Replies Last reply
              0
              • GrecKoG GrecKo

                QAbstractListModel as a property type or a return type should work, using QObject instead is not the correct solution.
                Have you tried calling qRegisterMetaType?

                raven-worxR Offline
                raven-worxR Offline
                raven-worx
                Moderators
                wrote on last edited by raven-worx
                #6

                @GrecKo said

                using QObject instead is not the correct solution

                and why?
                Context properties also dont't require a type registration and still can be used as models. Since the cast / type-check anyway happens on the qobject instance.

                --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                If you have a question please use the forum so others can benefit from the solution in the future

                1 Reply Last reply
                0
                • GrecKoG Offline
                  GrecKoG Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on last edited by GrecKo
                  #7

                  Because you lose the type information than can be used by the QML engine/compiler and Qt Creator.
                  Also root context properties should not be used anymore, access lookup is heavy for them.

                  1 Reply Last reply
                  0
                  • GrecKoG GrecKo

                    QAbstractListModel as a property type or a return type should work, using QObject instead is not the correct solution.
                    Have you tried calling qRegisterMetaType?

                    C Offline
                    C Offline
                    Curtwagner1984
                    wrote on last edited by Curtwagner1984
                    #8

                    @GrecKo said in Is it possible to pass an instance of a derived `QAbstractListModel` from backend to QML without using `setContextProperty`?:

                    Have you tried calling qRegisterMetaType?

                    No, I have not. I tried

                    qmlRegisterType(QAbstractListModel, "com.videoModel", 1, 0, "VideoModel")
                    
                    1 Reply Last reply
                    0
                    • C Offline
                      C Offline
                      Curtwagner1984
                      wrote on last edited by
                      #9

                      @GrecKo Could you elaborate on how to use qRegisterMetaType? And on what you mean by

                      root context properties should not be used anymore, access lookup is heavy for them.

                      1 Reply Last reply
                      0

                      • Login

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