Can't bind a Python function to a QML button

Question:

I’ve been struggling with binding QT Quick Application front-end and back-end. Here’s my code. For a clear and short example the function prints "Hello from back-end" as an output without getting any arguments.

main.py

from pathlib import Path
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine, QmlElement
from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot

class Calculator(QObject):
    def __init__(self):
        QObject.__init__(self)

    @pyqtSlot()
    def greet(self):
        print("Hello from backend")



if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    backend = Calculator()
    engine.rootContext().setContextProperty("backend", backend)
    engine.load("main.qml")

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

main.qml

import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs

ApplicationWindow {
    id: mainWindow    
    ...
    Button { 
        objectName: "checkButton"
        id: modelCheck
        text: qsTr("Check model")
        onClicked: backend.greet()
    }
     
    Connections {
        target: backend
        function onSignalPrintTxt(boolValue) {
            return
        }
    }     
}

When running this code, I get the following error:

TypeError: Property 'greet' of object QVariant(PySide::PyObjectWrapper, 0x1006571f0) is not a function

What am I doing wrong?

Asked By: Philipp Lazarev

||

Answers:

You appear to mixing pyside with pyqt.

To make a pyside only solution, I use QObject and Slot from pyside and updated the signature of greet. The rest of the code is your code.

# main.py
import sys
from pathlib import Path
from PySide6.QtCore import Qt, QObject, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine

class Calculator(QObject):
    def __init__(self):
        QObject.__init__(self)

    @Slot()
    def greet(self):
        print("Hello from backend")

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    backend = Calculator()
    engine.rootContext().setContextProperty("backend", backend)

    qml_file = Path(__file__).parent / "main.qml"
    engine.load(qml_file)

    if not engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec())
// main.qml
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Window

ApplicationWindow {
    id: main
    title: qsTr("Hello World")
    width: 640
    height: 480
    visible: true

    Button {
        id: modelCheck
        text: qsTr("Check model")
        onClicked: backend.greet()
    }
}
Answered By: Stephen Quan
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.