Calling QML functions from C++ [SOLVED]
-
I need to send/insert string value to the qml TextArea conmponent, from c++. I decided to use qml function, which would recieve the string value and then insert it to the TextArea.insert(). But when i do it, my application suddenly closes...
qml function code:
@function insertText(QString, msg) {
textArea.insert(msg);
}@C++ code:
@QString msg = "Hello from C++";
QMetaObject::invokeMethod(object, "insertText",
Q_ARG(QString, msg));@Final goal is to read file by c++ fstream library into QString and show it content on the application screen. Help me with solution!
-
Try something like this:
@// in this case this is the root QML object
function foo(msg) {
console.log(msg)
}@And in C++
@
QMetaObject::invokeMethod(engine.rootObjects().at(0), "foo", Q_ARG(QVariant, QVariant::fromValue(QString("blabla"))));@In JS you don't have types in the function parameters, only identifier, so remove that QString, and BTW in QML it is string, not QString
And in C++ you have to use a variant and pass the value in a QVariant.
Also, the fact that your application "closes" signifies there is something wrong, for example, the object you pass to invokeMethod() is not valid. If that method fails to locate the function, you will only get an error in the console, but your app will continue running normally. So most likely your object is not valid.
If the QML function is not in the root element, set its objectName property to someText and use the root item's findChild() method to find the child with the someText name, check if it is indeed found and only then use it in invokeMethod()
@QObject * object = engine.rootObjects().at(0)->findChild<QObject*>("someText");@
-
The first way gave an error:
ASSERT failure in QList<T>::at: "index out of range"
I try to do it like this:
@QObject * object = engine.rootObjects().value(0)->findChild<QObject*>("algoShow");
QMetaObject::invokeMethod(object, "insertText",
Q_ARG(QVariant, QVariant::fromValue(QString("Hello from c++!"))));@or like this:
@QObject * object = engine.findChild<QObject*>("algoShow");@
and QML:
@function insertText(msg) {
console.log(msg);
}@But nothing happened, i think that function was not invoked..
-
bq. ASSERT failure in QList<T>::at: “index out of range”
Do you have any QML created at the time you try that? If you don't have the first element in root objects, then you probably don't have anything at all, you HAVE TO HAVE root before you can have anything else. You are probably doing it before any QML is loaded.
The reason you don't get the out of range error with value() is because this method returns a default constructed value if nothing is found, so you get a null pointer, which is why invoke method doesn't do anything.
Make sure you have your QML loaded before you try to access it.
@engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // or whatever your main QML file is@
-
Oh, i loaded main,qml, right like you wrote. But then i also created two qml files directly from qml document, in this way:
in main.cpp I load main.qml:
@Manager manager;
engine.load(QUrl(mainPath));
object = engine.rootObjects().value(0);
engine.rootContext()->setContextProperty("myObj", &manager);@in main.qml I load the second qml file :
@ApplicationWindow {
id: mainWindow
property variant win;button {
...
onClicked: {var component = Qt.createComponent("qrc:/Smejnost.qml"); win = component.createObject(mainWindow); win.show(); }
}}@
Maybe you can suggest a better way, how to load and manage qml files. I'm just a beginner :)
-
Well, you don't honestly expect that you will be able to find the object in C++ main() before it was created in QML, right?
There is nothing wrong with the way you create the Smejnost component, and regardless of the style of creation, you will always need to have it created before you can locate it with findChild().
You just have to put your call from C++ to QML in the proper "spot", not simply in main, because it will run immediately after the main component is set, before you have the chance to create extra components from QML.
But if you really want to put it in main, you can use a signal, add a signal to the ApplicationWindow, in main() find the main object and connect that signal to a free function or lambda which wraps the findChild() and inkoveMethod() call, and from QML emit the signal when Smejnost has been created. This way you will attempt to find the target component only after it is created.
-
-
YES ! I just load qml file like in qt tutorial, and it's worked !
@QQmlEngine engine;
QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/Algo_Show.qml")));
QObject *object = component.create();
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "insertText",
Q_ARG(QVariant, msg));
@Like i said before, i'm just a begginer ) But the problem solved! Thanks.
-
Yes, you could have created the QML object from C++ as well. All this is for the sake of getting a test to work I guess, you will have to figure out how to lay out your actual application so you avoid the "chicken or egg" paradox.
And since you already use Qt, you might as well be using QFile instead of fstream.