Search code examples
pythonqtpyqtqmlqt-quick

How do you bind buttons in Qt Quick to Python (PyQt)?


I want to click a button made in QML and execute a function that's defined in my Python (PyQt) code. How do I do that?

main.py:

    import sys
    from PyQt5.QtCore import QObject, QUrl, Qt
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtQml import QQmlApplicationEngine

    if __name__ == "__main__":
      app = QApplication(sys.argv)
      engine = QQmlApplicationEngine()
      ctx = engine.rootContext()
      ctx.setContextProperty("main", engine)

      engine.load('test.qml')

      win = engine.rootObjects()[0]
      win.show()
      sys.exit(app.exec())

main.qml:

    import QtQuick 2.2
    import QtQuick.Window 2.1
    import QtQuick.Controls 1.2
    import QtQuick.Dialogs 1.1

    ApplicationWindow {
     title: qsTr("Test Invoke")

     width: 200
     height: 100

     Button{
      y : 70
      text : "About"
      onClicked: {
       print('Hello')
      }
     }
    }

Solution

  • If you name the button, you can connect to its onClick signal, or to a custom signal that it emits in onClicked. Example:

    ApplicationWindow {
     title: qsTr("Test Invoke")
     width: 200
     height: 100
    
     Button {
      signal messageRequired
      objectName: "myButton"
      y : 70
      text : "About"
      onClicked: messageRequired()
    
     }
    }
    

    Note the signal in Button and the objectName property. Then the Python code just before exec could be for example:

    def myFunction():
        print 'handler called'
    
    button = win.findChild(QObject, "myButton")
    button.messageRequired.connect(myFunction)
    button.clicked.connect(myFunction) # works too
    

    Note that in the Button above, onClicked just emits the messageRequired signal, so it is better to drop the custom signal and connect to clicked directly. Both onClicked() and any slots connected to clicked will get called when you click button.