Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Unable to store javascript callback in C++?



  • I am trying to pass a javascript callback to a C++ slot and then call that callback again after some time has passed, for example after an http request returns. It appears as though the QJSValue becomes corrupt after the call to the C++ slot stack frame is cleaned up. How is it possible to store a callback in c++ and then call it later?

    The following pyqt5 example demonstrates how the callback is passed correctly to the slot as a callable QJSValue but becomes not callable if referenced after the slot returns, i.e. through a timer.

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtQml import *
    from PyQt5.QtQuick import *
    from PyQt5.QtQuickWidgets import *
    
    
    class Widget(QWidget):
        def __init__(self):
            super().__init__()
            self._callback = None
            self.qml = QQuickWidget(self)
            self.qml.rootContext().setContextProperty('widget', self)
            self.qml.setSource(QUrl.fromLocalFile('test_qml.qml'))
            self.startTimer(10)
    
        @pyqtSlot(QJSValue)
        def doCallback(self, callback):
            print('doCallback: callable?', callback.isCallable(),
                  'isNull?', callback.isNull())
            self._callback = callback
            
        def timerEvent(self, e):
            if self._callback is not None:
                print('timerEvent: callable?',
                      self._callback.isCallable(), 'isNull?',
                      self._callback.isNull())
                if self._callback.isCallable():
                    self._callback.call([1, 2])
                self._callback = None
    
    import sys
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    app.exec()
    

    test_qml.qml

    import QtQuick 2.14
    
    Item {
        function callback() {
            print('callback()')
        }
        Component.onCompleted: widget.doCallback(callback)
    }
    

    prints the following output:

    patrick$ python test_qml.py
    doCallback: callable? True isNull? False
    timerEvent: callable? False isNull? False
    patrick$ 
    

Log in to reply