I have a c++ Q_INVOKABLE function that starts an asynchronous operation (image downloading). I want to pass a QML callback to the function for when the operation finishes.
I know that it could be done with QJSValue, but this way the callback is not called in the GUI thread so when I try to update some QML element, it prints an error and crashes the application: Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()
. Also, that question is 5 years old and maybe a better way has been introduced since then.
This is my QML code:
Rectangle {
// ...
Loader {
id: loader
source: "[loading animation]";
}
Component {
id: imageView
Image {
id: image
// ...
}
}
Component.onCompleted: {
ImageLoader.start_loading(post_id, function () {
loader.sourceComponent = imageView;
});
}
And the c++ code:
void ImageLoader::start_loading(const QString & id, QJSValue on_finished)
{
ImageLoaderRunnable * runnable_raw = new ImageLoaderRunnable(id, this->m_cache);
connect(runnable_raw, &ImageLoaderRunnable::finished, [on_finished]() mutable {
if (on_finished.isCallable()) {
on_finished.call();
}
});
runnable_pool.start(runnable_raw);
}
Also, this method is unsafe since the QML object can be destroyed before the callback is called.