Unsolved C++ callback function "pointer" to QML javascript
-
Hi all
I know the way to pass a generic QML function "pointer" to be called from C++ using QJSValue object, but how can be done the opposite? I need to know a way to pass to QML javascript code a generic C++ function callback "pointer" to be called from QML when a specific operation is finished.
How can be done?
Thank you -
@Suppaman Generally speaking Qt doesn't use callbacks because it has the signal/slot mechanism. Define the signal and the slot in a C++ class and expose it to QML. In C++ connect the signal to the slot. In QML call the signal as a function. The connected slot is called. In that way QML doesn't need to know about the slot, it works like a callback. The signal can of course be connected to any slot or no slot at all.
-
I know but in this case the QML side have to know the function sigina/slot name that is not what I need. Using QJSValue object I can pass a generic QML function (different every time) to C++ that can be called (by suing call()) without know the javascript function name passed. I used the term "callback" just for explaim this use. I need a way to make the opposite, that's mean invoke a QML javascript function from C++ side and pass a C++ fuction (every time different) to be called from QML javascript once done a specific operation (for example ask for a Yes/No choice, since in QML doesn't exist blocking calls and need to make all asyncronous).
-
@Suppaman You can register classes to Qml which are not creatable by Qml, but can be used by QML:
qmlRegisterUncreatableType<InputDeviceConfigurator>( "InputDeviceConfigurator", 1, 0, "InputDeviceConfigurator", "Not creatable in Qml." );
The class must still be derived from QObject and functions must be prefixed with Q_INVOKABLE:
Q_INVOKABLE virtual QString descriptionString() = 0;
Now you can create objects in C++, pass only the pointer to Qml and call the functions from there.
Here is some more documentation: http://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html
-
@Suppaman said in C++ callback function "pointer" to QML javascript:
I know but in this case the QML side have to know the function sigina/slot name that is not what I need.
I don't know if I undersand you completely, but the QML side doesn't have to know the slot name if you have connected it in C++.
Let's take a traditional Observer patter for example (edit: https://en.wikipedia.org/wiki/Observer_pattern). I understood you want something like that, except that you want to register a C++ function to observe a javascript (QML) notification. You can replace the addObserver with "connect(...)" in C++ and observer.notify() with "this_is_a_cpp_signal_name_which_is_called_as_a_function_inside_qml_javascript_function()" in QML/javascript. No knowledge of slots needed in QML side.
-
I'll try to make a pratical example. I have the following C++ code:
MyClass::function_1() { // Make some operation } MyClass::function_2() { // Make some operation } MyClass::askForOperationToDo() { QMetaObject::invokeMethod(qmlObject, "askQmlMessageBox", Q_ARG(QVariant, function_1()) Q_ARG(QVariant, function_2()) ); }
On qml side I have this:
function askQmlMessageBox(funcAccept, funcReject) { var messageBox = Qt.createQmlObject("import QtQuick 2.7; import Qt.labs.platform 1.0;" + "MessageDialog { text:'some text here'; buttons: MessageDialog.Yes | MessageDialog.No; }", parentItem ); messageBox.accepted.connect(funcAccept) messageBox.rejected.connect(funcReject) messageBox.open(); }
Please note this example code was written on the fly just for help in explain and, obviously, will not work on real mode. The call to function "askForOperationToDo()" should invoke the qml function "askQmlMessageBox" and. in the way I don't know yet, pass "pointer" (or something similar) to function_1() and function_2() (in this example case, in the reality each call can have different functions). In Qml side these functions must to be connected to accept and reject event of qml MessageDialog and be called based to the choice of user.
Is possible to do this and which way could be better?
Obviously thank you to all for find time in help me -
@Suppaman You still haven't demonstrated why you need to have a "pointer" to C++ function in QML. You could wrap the function call through a pointer-to-function within a C++ slot. For example
function askQmlMessageBox() { ... messageBox.accepted.connect(messageBox.slotAccept) //provided this works
MyClass::askForOperationToDo() { this->pointerToMemFn1 = &MyClass::function_1; QMetaObject::invokeMethod(qmlObject, "askQmlMessageBox" ); } MyClass::slotAccept() { (this->*pointerToMemFn1)(); }
I don't know if it's possible to do as you would like; I just point out it's not necessary.
-
I put the word "pointer" between quotation marks just for use as example to explain what I need but it seem I'm not able to explain well. My software have the core code written in C++ and the interface with QML. I want to create a general purpose QML messagebox to use from C++. The problem here is QML is always asyncrouns than I can not show a modal messagebox and wait for the reply of the user like in C++ can be done using exec() function. This mean I need a genaral QML code to use by passing the text to show inside messagebox and the C++ functions to call in case of accept or reject event. I know the ways can be multiple but I would to know if there is a way to pass a function reference from C++ to QML to connect (from QML) to accepted and rejected events. You solution is the more easiest way but is not very elegant, if there isn't a bettern alternative I use something similar but, just in case, I asked before...
-
@Suppaman It looks like I understood you correctly (and used "pointer" for the same reason than you did). I agree that my solution isn't as elegant than using pointer-to-function syntax between C++ and QML would be.
QML recognizes only certain Qt data types and function pointer isn't one of them, so I don't see a way to do it in such an elegant way. But fellow Qt coders may come up with something.
-
Anyway I really thank you for the time you spent in try helping me, in any case it was really appreciated. ^_^