Asynchronous call from QML to Python with callback

Marcus Ottosson

From QML, I'd like to:

  1. Call a Python slot.
  2. Pass along a callback.
  3. Have that callback be run once the slot is complete.

I've tried this:

  1. Register a context-property (Service)
  2. Call Service.request("data", function (response) { console.log(response) }
  3. In Python, the function is received as a QtQml.QJSValue
  4. The function is called in a separate thread, after some expensive operation

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

three_pineapples

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.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to construct callback to deal with asynchronous return from API call

From Dev

Node.js: Making a call to asynchronous parent function from within asynchronous child function's callback

From Dev

ReactJS setState from asynchronous callback

From Dev

Asynchronous call in for loop cause variable to be wrong in callback

From Dev

When calling multiple C++ functions from QML and the first function contains a connect call, the QML continues before the callback is triggerd

From Dev

Access Python QObject from QML fails to convert on second call

From Java

How to return value from an asynchronous callback function?

From Dev

Asynchronous callback from web api controller

From Dev

Returning Data from Service to Controller with Asynchronous Callback

From Dev

Returning response from asynchronous call

From Dev

How does a callback/closure know to wait after Asynchronous call is finished?

From Dev

Call Sync method call from Async Callback?

From Dev

Asynchronous call from list item of recycler view

From Dev

Reload UITable call from asynchronous function

From Dev

Getting just an object back from an asynchronous call

From Dev

returning a value from asynchronous call using semaphores

From Dev

Return response from asynchronous call example

From Dev

Asynchronous call from Application_Error()

From Dev

Making an asynchronous AJAX call from within Laravel

From Dev

Getting just an object back from an asynchronous call

From Dev

Store data from asynchronous call to a variable in AngularJS

From Dev

Return response from asynchronous call example

From Dev

Asynchronous call from list item of recycler view

From Dev

call QML function from C++ with another QML object as parameter

From Dev

Push object into local array from asynchronous callback function

From Dev

Push object into local array from asynchronous callback function

From Dev

How to call slot with QFlags argument from QML

From Dev

call method from inside callback using typescript

From Dev

Call private method of object from callback

Related Related

  1. 1

    How to construct callback to deal with asynchronous return from API call

  2. 2

    Node.js: Making a call to asynchronous parent function from within asynchronous child function's callback

  3. 3

    ReactJS setState from asynchronous callback

  4. 4

    Asynchronous call in for loop cause variable to be wrong in callback

  5. 5

    When calling multiple C++ functions from QML and the first function contains a connect call, the QML continues before the callback is triggerd

  6. 6

    Access Python QObject from QML fails to convert on second call

  7. 7

    How to return value from an asynchronous callback function?

  8. 8

    Asynchronous callback from web api controller

  9. 9

    Returning Data from Service to Controller with Asynchronous Callback

  10. 10

    Returning response from asynchronous call

  11. 11

    How does a callback/closure know to wait after Asynchronous call is finished?

  12. 12

    Call Sync method call from Async Callback?

  13. 13

    Asynchronous call from list item of recycler view

  14. 14

    Reload UITable call from asynchronous function

  15. 15

    Getting just an object back from an asynchronous call

  16. 16

    returning a value from asynchronous call using semaphores

  17. 17

    Return response from asynchronous call example

  18. 18

    Asynchronous call from Application_Error()

  19. 19

    Making an asynchronous AJAX call from within Laravel

  20. 20

    Getting just an object back from an asynchronous call

  21. 21

    Store data from asynchronous call to a variable in AngularJS

  22. 22

    Return response from asynchronous call example

  23. 23

    Asynchronous call from list item of recycler view

  24. 24

    call QML function from C++ with another QML object as parameter

  25. 25

    Push object into local array from asynchronous callback function

  26. 26

    Push object into local array from asynchronous callback function

  27. 27

    How to call slot with QFlags argument from QML

  28. 28

    call method from inside callback using typescript

  29. 29

    Call private method of object from callback

HotTag

Archive