From QML, I'd like to:
I've tried this:
Service
)Service.request("data", function (response) { console.log(response) }
QtQml.QJSValue
However, the function only has an effect sometimes, and most of the time not at all or crashes the Python interpreter. If I remove the call to time.sleep(1)
, it is more likely to produce results.
Any ideas?
Here's a non-working implementation of the above
main.qml
import QtQuick 2.3
import "application.js" as App
Rectangle {
id: appWindow
width: 200
height: 200
Component.onCompleted: App.onLoad()
}
main.py
import sys
import time
import threading
from PyQt5 import QtCore, QtGui, QtQml, QtQuick
class Service(QtCore.QObject):
def __init__(self, parent=None):
super(Service, self).__init__(parent)
@QtCore.pyqtSlot(str, str, QtCore.QVariant, QtQml.QJSValue)
def request(self, verb, endpoint, data, cb):
"""Expensive call"""
print verb, endpoint, data
self.cb = cb
def thread():
time.sleep(1)
event = QtCore.QEvent(1000)
event.return_value = "expensive result"
QtGui.QGuiApplication.postEvent(self, event)
worker = threading.Thread(target=thread)
worker.daemon = False
worker.start()
self.worker = worker
def event(self, event):
if event.type() == 1000:
self.cb.call([event.return_value])
return super(Service, self).event(event)
app = QtGui.QGuiApplication(sys.argv)
view = QtQuick.QQuickView()
context = view.rootContext()
service = Service()
context.setContextProperty("Service", service)
view.setSource(QtCore.QUrl("main.qml"))
view.show()
app.exec_()
application.js
"use strict";
/*global print, Service*/
function onLoad() {
Service.request("POST", "/endpoint", {"data": "value"}, function (reply) {
print(reply);
print(reply);
print(reply);
});
print("request() was made");
}
The implementation is adapted from here
https://github.com/ben-github/PyQt5-QML-CallbackFunction
Best,
Marcus
There is no indication from the documentation that QJSValue
is thread safe. This page indicates the classes that are re-entrant or thread safe are marked as such in the documentation. However, there is no mention of the word thread on the page for QJSValue
.
As such, I would suggest you make sure that your callback is only called from the main thread. Obviously, you are still going to want to put your long running task in a thread, so I would suggest using something like QCoreApplication.postEvent()
to send an event from your Python thread to the main thread, which will then call your callback function.
Note: I've wrapped calls to QCoreApplication.postEvent
for PyQt4 here. If you need help understanding how to use the QCoreApplication.postEvent
method, you can probably adapt it to work with PyQt5 as well.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments