Issue
I was writing a large program and encountered strange errors. Wandering around Google, I came to a simple program that does not perform the expected functionality.
When you press a button, the number should increase and be displayed in the console and in the field. But for some reason the number is only displayed in the console. Moreover, if in qml you replace the function call with any line, then the line after clicking will be shown.
So this is interface in qml
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 400
height: 200
title: "PySide QML Example"
Rectangle {
anchors.fill: parent
Button {
text: "Increment"
onClicked: {
textField.text = backend.increment_counter().toString();
}
}
TextField {
id: textField
anchors.centerIn: parent
readOnly: true
}
}
}
And this is simple program
import sys
from PySide6.QtCore import Qt, QUrl, Slot, QObject
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Backend(QObject):
def __init__(self):
super().__init__()
self.counter = 0
@Slot()
def increment_counter(self):
self.counter += 1
print(self.counter)
return self.counter
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
backend = Backend()
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("backend", backend)
qml_file = "main.qml"
engine.load(QUrl.fromLocalFile(qml_file))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
I tried reinstalling pyside packages. And perhaps this will help: in a large program, the Component.onCompleted method did not work for me and methods from Python that were written inside qml were not called
Solution
As per @musicamante comment, it would be better for you provide a property with a change signal alongside your method:
- counter Property()
- counter_changed Signal()
- increment_counter() Slot()
I cleaned up your implementation of increment_counter
to perform the increment but not return the value. The returning of the value will be done through the property.
As a property, we can clean up the QML code so that the Button
onClicked only invokes the slot, but, the TextField
is directly bound to the counter
property.
# main.py
import sys
from PySide6.QtCore import Qt, QUrl, Slot, QObject, Property, Signal
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Backend(QObject):
def __init__(self):
super().__init__()
self._counter = 0
counter_changed = Signal()
def get_counter(self):
return self._counter
def set_counter(self, val):
self._counter = val
self.counter_changed.emit()
@Slot()
def increment_counter(self):
self.set_counter(self.get_counter() + 1)
counter = Property(int, get_counter, set_counter, notify=counter_changed)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
backend = Backend()
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("backend", backend)
qml_file = "main.qml"
engine.load(QUrl.fromLocalFile(qml_file))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 400
height: 200
title: "PySide QML Example"
Rectangle {
anchors.fill: parent
Button {
text: "Increment"
onClicked: backend.increment_counter()
}
TextField {
id: textField
anchors.centerIn: parent
readOnly: true
text: backend.counter
}
}
}
Answered By - Stephen Quan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.