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. My qml doesn't find my model from python
Forum Updated to NodeBB v4.3 + New Features

My qml doesn't find my model from python

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 2 Posters 1.5k 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.
  • L Offline
    L Offline
    le-fab.
    wrote on last edited by le-fab.
    #1

    Hello here is a simple test to fill a ListView from ma python main file, I have the following error:
    file:/// ..... /main.qml:26: ReferenceError: elements is not defined

    here is the qml file

    import QtQuick 2.9
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.4
    import PyModels 1.0
    
    Window {
        id: window
        visible: true
        width: 640
        height: 460
        title: qsTr("Test")
        
        Button {
            id: btn
            text: qsTr("fill model")
            onClicked: {
                py_mainapp.fillModel()
            }
        }
    
        ListView {
                anchors.top: parent.top
                anchors.left: btn.right
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                model: elements.items
                delegate: Item {
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height: 24
                    Row {
                        anchors.fill: parent
                        Label {
                            text: model.name
                        }
                        Label {
                            text: model.title
                    }
                }
            }
        }     
        
    }
    

    Here is the py file

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    import os
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtQml import QQmlApplicationEngine, QQmlListProperty, qmlRegisterType
    from PyQt5.QtCore import pyqtSlot, QObject, QVariant,pyqtProperty
    
    
    class ListElementPy(QObject):
    
        def __init__(self, name, title):
            super(ListElementPy, self).__init__()
            self._title = title
            self._name = name
            
        @pyqtProperty('QString')
        def title(self):
            return self._title
    
        @title.setter
        def title(self, avalue):
            if avalue != self._title:
                self._title = avalue
                    
        @pyqtProperty('QString')
        def name(self):
            return self._name
            
        @name.setter
        def name(self, avalue):
            if avalue != self._name:
                self._name = avalue
                    
    
    class ElementsPy(QObject):
        
        def __init__(self):
            super(ElementsPy, self).__init__()
            self._items = []
            
        @pyqtProperty('QString')
        def items(self):
            return QQmlListProperty(ListElementPy, self, self._items)
           
        def append(self, avalue):
            self._items.append(avalue)
                    
    
    class MainApp(QObject):
    
        def __init__(self, context, parent):
            super(MainApp, self).__init__(parent)
            self.win = parent
            self.ctx = context
            self.elements = ElementsPy()
            
    
        @pyqtSlot()
        def fillModel(self):
            for x in range (1,50):
                self.elements.append(ListElementPy("name %.0f" % (x), "title %.0f" % (x)))
                
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        qmlRegisterType(ListElementPy, "PyModels", 1, 0, "ListElementPy")
        qmlRegisterType(ElementsPy, "PyModels", 1, 0, "ElementsPy")
        engine = QQmlApplicationEngine()
        ctx = engine.rootContext()
        engine.load("main.qml")
        win = engine.rootObjects()[0]
        py_mainapp = MainApp(ctx, win)
        ctx.setContextProperty("py_mainapp", py_mainapp)
        ctx.setContextProperty("elements", py_mainapp.elements)
        win.show()
        sys.exit(app.exec_())
    
    

    What am I doing wrong?
    py_mainapp is found in the qml, but not elements

    L 1 Reply Last reply
    0
    • L le-fab.

      Hello here is a simple test to fill a ListView from ma python main file, I have the following error:
      file:/// ..... /main.qml:26: ReferenceError: elements is not defined

      here is the qml file

      import QtQuick 2.9
      import QtQuick.Window 2.2
      import QtQuick.Controls 1.4
      import PyModels 1.0
      
      Window {
          id: window
          visible: true
          width: 640
          height: 460
          title: qsTr("Test")
          
          Button {
              id: btn
              text: qsTr("fill model")
              onClicked: {
                  py_mainapp.fillModel()
              }
          }
      
          ListView {
                  anchors.top: parent.top
                  anchors.left: btn.right
                  anchors.right: parent.right
                  anchors.bottom: parent.bottom
                  model: elements.items
                  delegate: Item {
                      anchors.left: parent.left
                      anchors.right: parent.right
                      height: 24
                      Row {
                          anchors.fill: parent
                          Label {
                              text: model.name
                          }
                          Label {
                              text: model.title
                      }
                  }
              }
          }     
          
      }
      

      Here is the py file

      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      import sys
      import os
      from PyQt5.QtWidgets import QApplication
      from PyQt5.QtQml import QQmlApplicationEngine, QQmlListProperty, qmlRegisterType
      from PyQt5.QtCore import pyqtSlot, QObject, QVariant,pyqtProperty
      
      
      class ListElementPy(QObject):
      
          def __init__(self, name, title):
              super(ListElementPy, self).__init__()
              self._title = title
              self._name = name
              
          @pyqtProperty('QString')
          def title(self):
              return self._title
      
          @title.setter
          def title(self, avalue):
              if avalue != self._title:
                  self._title = avalue
                      
          @pyqtProperty('QString')
          def name(self):
              return self._name
              
          @name.setter
          def name(self, avalue):
              if avalue != self._name:
                  self._name = avalue
                      
      
      class ElementsPy(QObject):
          
          def __init__(self):
              super(ElementsPy, self).__init__()
              self._items = []
              
          @pyqtProperty('QString')
          def items(self):
              return QQmlListProperty(ListElementPy, self, self._items)
             
          def append(self, avalue):
              self._items.append(avalue)
                      
      
      class MainApp(QObject):
      
          def __init__(self, context, parent):
              super(MainApp, self).__init__(parent)
              self.win = parent
              self.ctx = context
              self.elements = ElementsPy()
              
      
          @pyqtSlot()
          def fillModel(self):
              for x in range (1,50):
                  self.elements.append(ListElementPy("name %.0f" % (x), "title %.0f" % (x)))
                  
      
      if __name__ == "__main__":
          app = QApplication(sys.argv)
          qmlRegisterType(ListElementPy, "PyModels", 1, 0, "ListElementPy")
          qmlRegisterType(ElementsPy, "PyModels", 1, 0, "ElementsPy")
          engine = QQmlApplicationEngine()
          ctx = engine.rootContext()
          engine.load("main.qml")
          win = engine.rootObjects()[0]
          py_mainapp = MainApp(ctx, win)
          ctx.setContextProperty("py_mainapp", py_mainapp)
          ctx.setContextProperty("elements", py_mainapp.elements)
          win.show()
          sys.exit(app.exec_())
      
      

      What am I doing wrong?
      py_mainapp is found in the qml, but not elements

      L Offline
      L Offline
      le-fab.
      wrote on last edited by le-fab.
      #2

      I added the following lines in the qml (which seems to me quite strange as I already defined elements in the python file)

      ElementsPy {
          id: elements
      }
      ListElementPy {
          property string name
          property string title
      }
      

      Now I have the following error:
      TypeError: init() takes 1 positional argument but 2 were given

      1 Reply Last reply
      0
      • L Offline
        L Offline
        le-fab.
        wrote on last edited by le-fab.
        #3

        ok, I've found on internet (https://riverbankcomputing.com/pipermail/pyqt/2017-January/038497.html) a solution working, so I'm gonna start with modifying the following code which works:
        qml:

        import QtQuick 2.9
        import QtQuick.Window 2.2
        import QtQuick.Controls 1.4
        
        import Example 1.0
        
        Window {
            width: 500
            height: 500
            visible: true
        
            ListView {
                anchors.fill: parent
                model: store.channels
                delegate: Item {
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height: 24
                    Row {
                        anchors.fill: parent
                        Label {
                            text: name
                        }
                        Label {
                            text: title
                        }
                    }
                }
            }
        }
        

        python:

        from sys import argv
        from PyQt5.QtWidgets import QApplication
        from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal
        from PyQt5.QtQml import QQmlListProperty, QQmlApplicationEngine, qmlRegisterType
                        
        class Channel(QObject):
        
            nameChanged = pyqtSignal()
            titleChanged = pyqtSignal()
        
            def __init__(self, name='', title='', *args, **kwargs):
                super().__init__(*args, **kwargs)
                self._name = name
                self._title = title
        
            @pyqtProperty('QString', notify=nameChanged)
            def name(self):
                return self._name
        
            @name.setter
            def name(self, name):
                if name != self._name:
                    self._name = name
                    self.nameChanged.emit()
                    
            @pyqtProperty('QString', notify=nameChanged)
            def title(self):
                return self._title
        
            @title.setter
            def title(self, title):
                if title != self._title:
                    self._title = title
                    self.titleChanged.emit()
        
        class Store(QObject):
        
            channelsChanged = pyqtSignal()
        
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self._channels = [
                    Channel('aa', 'AAA'),
                    Channel('bb', 'BBB')
                ]
        
            @pyqtProperty(QQmlListProperty, notify=channelsChanged)
            def channels(self):
                return QQmlListProperty(Channel, self, self._channels)
        
            @channels.setter
            def channels(self, channels):
                if channels != self._channels:
                    self._channels = channels
                    self.channelsChanged.emit()
        
            def appendChannel(self, channel):
                self._channels.append(channel)
                self.channelsChanged.emit()
        
        
        def main():
            app = QApplication(argv)
        
            qmlRegisterType(Channel, 'Example', 1, 0, 'Channel')
            qmlRegisterType(Store, 'Example', 1, 0, 'Store')
        
            store = Store()
        
            engine = QQmlApplicationEngine()
            engine.rootContext().setContextProperty('store', store)
            engine.load('main.qml')
        
            # After 3 seconds, we append a new Channel
            QTimer.singleShot(3000, lambda: store.appendChannel(Channel('cc', 'CCC')))
        
            exit(app.exec_())
        
        
        if __name__ == '__main__':
            main()
        
        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #4

          The problem is in your delegate. The syntax is role.property not modelName.property. See this wiki post (the code is C++ but there's no real difference in python)

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          1

          • Login

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