PySide6 Signal - QtQuick Slot Using QQmlApplicationEngine.setInitialProperties()

In the previous example we’ve had a PySide6 signal, a Qml slot, and the connection is made in PySide6. In this one we still have a PySide6 signal and a Qml slot but we connect them in the Qml file. To do this

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts


ApplicationWindow {

    id: mainWindow

    visible: true
    width: 400
    height:200
    title: "Template App"
    
    // 1. Add a property named timer to the root object
    
    property variant timer
    
    RowLayout {
        
        anchors.fill: parent
            
        Label {
        
            id: label
        
            text: "Hello Qml!"

            Layout.fillWidth: true
            Layout.fillHeight: true
            
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            
            font.pointSize:24
            font.bold: true
            color: "steelblue"
            
            // 3. Use the Qml Connections type to connect
            //    QTimer.timeout to the Qml slot
            //    Target is the slot owner (ie QTimer)
            //    and the slot name, onTimeout matches
            //    the signal name, timeout
            
            Connections {
            
                target: mainWindow.timer
                
                function onTimeout () {
                    label.text = 
                        Qt.formatTime(new Date, "hh:mm:ss")
                }
            }
        }
    }
}
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
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)

    # 2. Create a timer and set the root object
    #    timer property value to it.

    timer = QTimer()
    timer.start(1000)

    # it appears that you need to set properties
    # before loading the Qml file.
    
    engine.setInitialProperties({'timer': timer})
    engine.load('02_setinitialproperties.qml')
    
    root = engine.rootObjects()[0]
    label = root.findChild(QObject, 'label')

    result = app.exec()
    del engine
    
    sys.exit(result)
  1. Add a custom property to the Qml ApplicationWindow. Custom properties can be of any of the Qml value types like bool, int or string but as QTimer is an object we set the property type to variant (although var would also work).

  2. In the PySide6 file, create a QTimer object named timer and use QQmalApplicationEngine.setInitialProperties() to assign timer to the ApplicationWindow.timer property we created in 1. setInitialProperties() accepts a Python dictionary and in this case it has only one element. You need to setInitialProperties() before you load() the Qml file or the Qml engine will complain: Unable to assign [undefined] to QObject*.

  3. Back in Qml, use the Connections type to create the slot and connect the signal with it. Connections.target holds a reference to the object that emits the signal and the slot and the signal names need to match: the signal’s name is timeout so the slot needs to be named onTimeout. The slot sets the label’s text to the current time just as in the first example.