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. Communication between python and qml
Forum Updated to NodeBB v4.3 + New Features

Communication between python and qml

Scheduled Pinned Locked Moved Solved QML and Qt Quick
8 Posts 2 Posters 8.7k 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, I just started with python and qml and if have a problem with the communication between the qml and the py. In the following function in my python main app class only the first line works

        def foo(self, aword):
            print('from qml: %s was received' % (aword))
            o = self.win.findChild(QObject, 'lbl1')
            print("child: ", o)
            return 'a message from python'
    

    I receive the text sent from the qml, but "self.win.findChild" returns None, and in the qml, the text sent by python is undefined

    Here is the py file

    # -*- coding: utf-8 -*-
    import sys
    import images_rc
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtQml import QQmlApplicationEngine
    from PyQt5.QtCore import QObject, pyqtSlot, QVariant
    
    class MainApp(QObject):
    
        def __init__(self, context, parent=None):
            super(MainApp, self).__init__(parent)
            self.win = parent
            self.ctx = context
    
        @pyqtSlot(QVariant)
        def foo(self, aword):
            print('from qml: %s was received' % (aword))
            o = self.win.findChild(QObject, 'lbl1')
            print("child: ", o)
            return 'a message from python'
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        engine = QQmlApplicationEngine()
        ctx = engine.rootContext()
        engine.load('test.qml')
        win = engine.rootObjects()[0]
        py_mainapp = MainApp(ctx, win)
        ctx.setContextProperty("py_mainapp", py_mainapp)
        win.show()
        sys.exit(app.exec_())
    
    

    Here is the qml file

    import QtQuick 2.9
    import QtQuick.Controls 1.4
    
    Window {
        title: "Test"
        width: 400
        height: 300
    
        Label {
            id: lbl1
        }
    
        Label {
            id: lbl2
        }
    
        Button {
            text: 'pressme'
            onClicked: {
                lbl2.text = py_mainapp.foo('hello from qml')
            }
        }
    }
    

    Does anyone knows what am I doing wrong?

    Here are the logs:

    file:///Users/fabrice/Svn/qt/nasmediasPY/test.qml:20: Error: Cannot assign [undefined] to QString
    from qml: Hello from qml was received
    child: None

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

      Hello, I just started with python and qml and if have a problem with the communication between the qml and the py. In the following function in my python main app class only the first line works

          def foo(self, aword):
              print('from qml: %s was received' % (aword))
              o = self.win.findChild(QObject, 'lbl1')
              print("child: ", o)
              return 'a message from python'
      

      I receive the text sent from the qml, but "self.win.findChild" returns None, and in the qml, the text sent by python is undefined

      Here is the py file

      # -*- coding: utf-8 -*-
      import sys
      import images_rc
      from PyQt5.QtWidgets import QApplication
      from PyQt5.QtQml import QQmlApplicationEngine
      from PyQt5.QtCore import QObject, pyqtSlot, QVariant
      
      class MainApp(QObject):
      
          def __init__(self, context, parent=None):
              super(MainApp, self).__init__(parent)
              self.win = parent
              self.ctx = context
      
          @pyqtSlot(QVariant)
          def foo(self, aword):
              print('from qml: %s was received' % (aword))
              o = self.win.findChild(QObject, 'lbl1')
              print("child: ", o)
              return 'a message from python'
      
      
      if __name__ == "__main__":
          app = QApplication(sys.argv)
          engine = QQmlApplicationEngine()
          ctx = engine.rootContext()
          engine.load('test.qml')
          win = engine.rootObjects()[0]
          py_mainapp = MainApp(ctx, win)
          ctx.setContextProperty("py_mainapp", py_mainapp)
          win.show()
          sys.exit(app.exec_())
      
      

      Here is the qml file

      import QtQuick 2.9
      import QtQuick.Controls 1.4
      
      Window {
          title: "Test"
          width: 400
          height: 300
      
          Label {
              id: lbl1
          }
      
          Label {
              id: lbl2
          }
      
          Button {
              text: 'pressme'
              onClicked: {
                  lbl2.text = py_mainapp.foo('hello from qml')
              }
          }
      }
      

      Does anyone knows what am I doing wrong?

      Here are the logs:

      file:///Users/fabrice/Svn/qt/nasmediasPY/test.qml:20: Error: Cannot assign [undefined] to QString
      from qml: Hello from qml was received
      child: None

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @le-fab.

      o = self.win.findChild(QObject, 'lbl1')

      I know nothing about QML. But as per http://doc.qt.io/qt-5/qobject.html#findChild, isn't the first parameter supposed to be a string of the name of the object?? Is your findChild() function a special PyQt one?

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

        I guess it's some kind of binding, but I'm not sure. I'm going to try to remove the first parameter and test
        with self.win.findChild('lbl1'), Thanks for the advice

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

          I confirm self.win.findChild needs the QObject first parameter

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

            I confirm self.win.findChild needs the QObject first parameter

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #5

            @le-fab.
            OK. So I believe https://stackoverflow.com/questions/36273655/cannot-call-findchildqobject-child-on-qobject-returns-none answers your question from QML/PyQt? Or https://stackoverflow.com/questions/44816536/pyqt5-and-qml-integration-issue-with-findchild-returning-attributeerror. Maybe? :)

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

              Thanks for the links.
              self.win.findChild works, with the attribute objectName defined in the qml
              Know I have to find why the text sent from python isn't received in the qml

              If it can help here is the code to access a qml child's property:

              @pyqtSlot(QVariant)
                  def foo(self, aword):
                          print('from qml: %s was received' % (aword))
                          o = self.win.findChild(QObject, 'pyLbl1')
                          print('text from label', o.property("text"))
                          return 'a message from python'
              
              JonBJ 1 Reply Last reply
              0
              • L le-fab.

                Thanks for the links.
                self.win.findChild works, with the attribute objectName defined in the qml
                Know I have to find why the text sent from python isn't received in the qml

                If it can help here is the code to access a qml child's property:

                @pyqtSlot(QVariant)
                    def foo(self, aword):
                            print('from qml: %s was received' % (aword))
                            o = self.win.findChild(QObject, 'pyLbl1')
                            print('text from label', o.property("text"))
                            return 'a message from python'
                
                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #7

                @le-fab.
                This is all way beyond my ken! But is it to do with either pyqtProperty or toPyObject? See http://pyqt.sourceforge.net/Docs/PyQt5/qt_properties.html, and https://wiki.python.org/moin/PyQt/Binding widget properties to Python variables where code claims:

                return type(self.findChild(QObject, objectName).property(propertyName).toPyObject())

                ? :)

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

                  I was reading something close to the solution you pointed: https://riverbankcomputing.com/pipermail/pyqt/2017-January/038497.html
                  I guess i'm going to use this kind of implementation to populate the qml.

                  I guess we can mark this post as solved because even if I can't read the string in the qml from my foo method, I know how to access and edit the qml child's properties with the win.findChild and the QObject.setProperty methods

                  Thanks for the help

                  Here is my final test code where everything is working:
                  main.py:

                  #!/usr/bin/env python
                  # -*- coding: utf-8 -*-
                  import sys
                  from PyQt5.QtWidgets import QApplication
                  from PyQt5.QtQml import QQmlApplicationEngine
                  from PyQt5.QtCore import QObject, pyqtSlot, QVariant
                  
                  class MainApp(QObject):
                  
                      def __init__(self, context, parent=None):
                          super(MainApp, self).__init__(parent)
                          self.win = parent
                          self.ctx = context
                  
                      @pyqtSlot(QVariant)
                      def foo(self, aword):
                              print('from qml: %s was received' % (aword))
                              o = self.win.findChild(QObject, 'pyLbl1')
                              print('text from label', o.property("text"))
                              o = self.win.findChild(QObject, 'pyLbl2')
                              o.setProperty("text", "some text from python")
                  
                  
                  if __name__ == "__main__":
                      app = QApplication(sys.argv)
                      engine = QQmlApplicationEngine()
                      ctx = engine.rootContext()
                      engine.load('test.qml')
                      win = engine.rootObjects()[0]
                      py_mainapp = MainApp(ctx, win)
                      ctx.setContextProperty("py_mainapp", py_mainapp)
                      win.show()
                      sys.exit(app.exec_())
                  
                  

                  test.qml:

                  import QtQuick 2.4
                  import QtQuick.Controls 1.4
                  
                  ApplicationWindow {
                      title: "Test"
                      width: 400
                      height: 300
                  
                      Column {
                          anchors.fill: parent
                          spacing: 10
                  
                          Label {
                              id: lbl1
                              objectName: 'pyLbl1'
                              text: "text in qml"
                          }
                  
                          Label {
                              id: lbl2
                              objectName: 'pyLbl2'
                              text: "unset"
                          }
                  
                  
                          Button {
                              text: 'pressme'
                              onClicked: {
                                  py_mainapp.foo('Hello from qml')
                              }
                          }
                      }
                  
                  }
                  

                  I guess I could have used the same name for id and objectName (the ids aren't used in this example anyway)

                  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