PyQt5 QML Signal to Python Slot?
Solution 1
qml_rectangle.mousePressEvent
is not a signal, it's an event handler that is called on mouse events, so you can't connect to it. You could just replace it with your handler function (qml_rectangle.mousePressEvent = on_qml_mouse_clicked
), but that's not a very clean way of working with Qt.
The better way would be to define a signal in your qml file and emit it from the rectangle's onClicked
handler:
import QtQuick 2.0
Rectangle {
signal clicked()
MouseArea {
anchors.fill: parent
onClicked: {
parent.clicked() // emit the parent's signal
}
}
}
Then you can just connect to it from your python code:
...
def on_qml_mouse_clicked():
print('mouse clicked')
qml_rectangle.clicked.connect(on_qml_mouse_clicked)
...
Solution 2
I would recommend sub classing QQuickView and setting a property on its root context, for example MainWindow. Now all you need to do is adding functions in that class with decorations such as @pyqtSlot('QString'), and then you can set the event handler with onClicked: MainWindow.FunctionName(Arguments_According_To_Decoration)
Then your main.py would look like this
#!/bin/env python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import QUrl
from PyQt5.QtQuick import QQuickView
from PyQt5.QtWidgets import QApplication
import sys
class MainWindow(QQuickView):
def __init__(self):
super().__init__()
self.setSource(QUrl('sample.qml'))
self.rootContext().setContextProperty("MainWindow", self)
self.show()
@pyqtSlot('QString')
def Print(self, value):
print(value)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
And sample.qml like so
import QtQuick 2.0
import QtQuick.Controls 2.2
Rectangle {
width: 200; height: 200
Button {
text: "print Hello World"
onClicked: MainWindow.Print('hello world')
}
}
You can find more information in the docs
http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html
berg
Updated on June 27, 2022Comments
-
berg almost 2 years
How can a python method/slot be connected to a QML signal? It looks like QtObject.connect() used to work in PyQt4 but it's no longer available in PyQt5.
#Sample QML File (stack.qml) import QtQuick 2.0 Rectangle { MouseArea { anchors.fill: parent onClicked: { // relay this to python } } }
--
#Sample Python File from PyQt5.QtCore import QUrl from PyQt5.QtGui import QGuiApplication from PyQt5.QtQuick import QQuickView if __name__ == '__main__': import os import sys app = QGuiApplication(sys.argv) view = QQuickView() view.setWidth(500) view.setHeight(500) view.setTitle('Hello PyQt') view.setResizeMode(QQuickView.SizeRootObjectToView) view.setSource(QUrl.fromLocalFile(os.path.join(os.path.dirname(__file__),'stack.qml'))) def on_qml_mouse_clicked(mouse_event): print 'mouse clicked' view.show() qml_rectangle = view.rootObject() # this technique doesn't work ############################# qml_rectangle.mousePressEvent.connect(on_qml_mouse_clicked) sys.exit(app.exec_())
Some of the PyQT examples pass an object into the QML context via "setContextProperty" and then relay QML events to slots on that object but that approach seems roundabout. Is there a better way?