PySide6 Signal - QtQuick Slot Using QObject.findChild()

In the Qt Widgets examples we’ve seen that a signal is emitted when an event occurs, that a slot is typically a Python method, and that you need to connect them for the mechanism to work. In a hybrid Pyside6/QtQuick application both PySide6 and Qml objects can emit signals, slots can be defined in both Python and Qml files and connections between them can be established either in Python or in Qml. This complicates things a bit but let’s start with a simple example. To use the signals and slots mechanism in a QtQuick application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts


ApplicationWindow {

    visible: true
    width: 400
    height:200
    title: "Template App"
    
    RowLayout {
        
        anchors.fill: parent
            
        Label {
        
            id: label
            objectName: "label"
        
            text: "Hello Qml!"

            Layout.fillWidth: true
            Layout.fillHeight: true
            
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            
            font.pointSize:24
            font.bold: true
            color: "steelblue"
            
            // 1. Add a slot function to the label
            
            function updateText () {
                label.text = "Timeout event\n"
                    + Qt.formatTime(new Date, "hh:mm:ss")
            }
        }
    }
}
  1. Add a function to a Qml object. In the example we start with the template Qml file and add a JavaScript function to the label. Qml comes with a JavaScript engine that lets you manipulate Qml objects and our function simply sets the label’s text to the current time when executed. Note that we also set two label’s properties: id and objectName. The id property is used to refer to an object from JavaScript code (as in label.text = ...). The objectName property sets QObject.objectName to the given string which is useful when you need to find the object using QObject’s findChild() or findChildren() methods. Note also that id is not a string.

In the Python file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import sys

from PySide6.QtCore import QObject, QTimer
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine


if __name__ == '__main__':

    app = QGuiApplication(sys.argv)
    
    engine = QQmlApplicationEngine()
    engine.quit.connect(app.quit)
    engine.load('01_rootobjects_findchild.qml')
    
    # 1. Find the Label element
    
    root = engine.rootObjects()[0]
    label = root.findChild(QObject, 'label')
    
    # 2. Create a timer and connect
    #    the timer signal to the label slot
    
    timer = QTimer()
    timer.timeout.connect(label.updateText)
    timer.start(1000)

    result = app.exec()
    del engine
    
    sys.exit(result)
  1. Get a reference to the Qml Label. Get the root Qml objects using QQmlApplicationEngine.rootObjects() - rootObjects() returns a list and ApplicationWindow is the first (and the only) element in it. As ApplicationWindow is ultimately a QObject we use QObject.findChild() to find the label.

  2. Create a QTimer instance and connect the timer’s timeout signal to the label’s updateText slot just as you would in a Qt Widgets application. Finally start the timer and the application itself.

That’s it - every time the timer ticks updateText is executed and the label’s text is updated. To recap, we have

  • a JavaScript function
  • a PySide6 signal
  • the connection is created in PySide6 code