QML function invoked from C++ not able to update element
I am invoking a QML function from C++. Issue is the QML function cannot update a QML element when invoked from C++. below is code:
In main.qml
:
import QtQuick 2.0
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
Text {
id: textbox
text: "nothing"
}
In main.cpp
:
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
The textbox element is just a regular text, and the text inside it remains "nothing", instead of the expected "Hello from C++".
Any ideas on how to solve this issue or in successfully passing arguments from C++ to QML?
c++ qt qml qqmlengine
add a comment |
I am invoking a QML function from C++. Issue is the QML function cannot update a QML element when invoked from C++. below is code:
In main.qml
:
import QtQuick 2.0
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
Text {
id: textbox
text: "nothing"
}
In main.cpp
:
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
The textbox element is just a regular text, and the text inside it remains "nothing", instead of the expected "Hello from C++".
Any ideas on how to solve this issue or in successfully passing arguments from C++ to QML?
c++ qt qml qqmlengine
2
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
1
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05
add a comment |
I am invoking a QML function from C++. Issue is the QML function cannot update a QML element when invoked from C++. below is code:
In main.qml
:
import QtQuick 2.0
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
Text {
id: textbox
text: "nothing"
}
In main.cpp
:
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
The textbox element is just a regular text, and the text inside it remains "nothing", instead of the expected "Hello from C++".
Any ideas on how to solve this issue or in successfully passing arguments from C++ to QML?
c++ qt qml qqmlengine
I am invoking a QML function from C++. Issue is the QML function cannot update a QML element when invoked from C++. below is code:
In main.qml
:
import QtQuick 2.0
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
Text {
id: textbox
text: "nothing"
}
In main.cpp
:
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
The textbox element is just a regular text, and the text inside it remains "nothing", instead of the expected "Hello from C++".
Any ideas on how to solve this issue or in successfully passing arguments from C++ to QML?
c++ qt qml qqmlengine
c++ qt qml qqmlengine
edited Nov 16 '18 at 10:08
TrebuchetMS
3,10011125
3,10011125
asked Nov 15 '18 at 16:01
SparkskieSparkskie
11
11
2
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
1
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05
add a comment |
2
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
1
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05
2
2
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
1
1
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05
add a comment |
2 Answers
2
active
oldest
votes
Lé Code
Qml
I'll assume that the qml code given actually belongs to MyItem.qml
instead of main.qml
.
Your Qml file generated an compile-time error. Functions should be placed inside an object, like so
// MyItem.qml
import QtQuick 2.0
Text {
id: textbox
text: "nothing"
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
}
I'm not sure how you were able to compile your project without generating an error, but I'm guessing either
- Your QtCreator/Qt version is not the same as mine (highly unlikely the cause); or
- You were try to making your code minimal and originally had a parent.
I'm sure you have a sufficient understanding about Qml so I'm not going to go deep into this.
C++
On the C++ side, I had to fiddle around with debug output to see what's wrong. Here's my main.cpp
:
// main.cpp
#include <QApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickItem>
int main(int argc, char *argv)
{
QApplication app(argc, argv); // Qt requires an instance of QApplication
QQmlEngine *engine = new QQmlEngine;
QString projectPath = "/Users/user/full/path/to/your/project"; // I'm on a Mac, but replace
// with the appropriate path to your project
// QQmlComponent component(engine, "MyItem.qml"); // this didn't work for me and
// set component.status() to QQmlComponent::Error
QQmlComponent component(engine, projectPath + "/qml/MyItem.qml"); // use full path
qDebug() << "Status:" << component.status();
if (component.status() == QQmlComponent::Error)
qDebug() << "Errors:" << component.errors();
else if (component.status() != QQmlComponent::Ready)
{
qDebug() << "Component is not ready!";
return 0;
}
QObject *object = component.create();
if (!object) { qDebug() << "Object creation failed!"; return 0; }
QQuickItem *item = qobject_cast<QQuickItem*>(object); // adding this didn't change much
// but this could be crucial
QVariant returnedValue;
QVariant msg = "Hello from C++";
bool success = QMetaObject::invokeMethod(item, "myQmlFunction", // replace `object` with `item`
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
if (success)
qDebug() << "QML function returned:" << returnedValue.toString();
else
qDebug() << "QMetaObject::invokeMethod returned false";
delete object;
return 0;
}
Output
The output I received on a successful build, with a successful object creation was
Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"
I haven't yet checked whether the text changed in your Qml textbox
. (Didn't bother to. It'll require more changes to the C++ code and this answer is already long enough. I was also confident that nothing'll go wrong, so ¯_(ツ)_/¯).
Lé Non-Code
What if I don't want to use a raw file path?
If you're meh about using a raw file path (e.g. /Users/whoami/ugly/looking/path
) in
QString projectPath = "/Users/user/full/path/to/your/project";
You can add this to your .pro
file:
DEFINES += SOURCE_PATH=$$PWD
and set projectPath
to
QString projectPath = QT_STRINGIFY(SOURCE_PATH);
This idea was borrowed from a forum thread.
Assumptions
Throughout my answer, I have assumed that your project hierarchy resembles
/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml
The essential thing is that you use your full path to your qml item. If you do find another to reference it (maybe using QUrl
?) then do post a comment about it.
Further Reading
Check out the details section of the QQmlComponent
class and QQmlComponent::create
member function. Reading these led me to know which values to debug and what to look out for.
add a comment |
Thanks for helping out,
I debugged it as well and the textbox.text was being overwritten with "Hello from C++" without the text in the window to be updated.
like eyllanesc suggested, I was creating a new engine object other than the already displayed window. (created elsewhere in the code)
after referencing the same object, the problem was solved.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323350%2fqml-function-invoked-from-c-not-able-to-update-element%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Lé Code
Qml
I'll assume that the qml code given actually belongs to MyItem.qml
instead of main.qml
.
Your Qml file generated an compile-time error. Functions should be placed inside an object, like so
// MyItem.qml
import QtQuick 2.0
Text {
id: textbox
text: "nothing"
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
}
I'm not sure how you were able to compile your project without generating an error, but I'm guessing either
- Your QtCreator/Qt version is not the same as mine (highly unlikely the cause); or
- You were try to making your code minimal and originally had a parent.
I'm sure you have a sufficient understanding about Qml so I'm not going to go deep into this.
C++
On the C++ side, I had to fiddle around with debug output to see what's wrong. Here's my main.cpp
:
// main.cpp
#include <QApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickItem>
int main(int argc, char *argv)
{
QApplication app(argc, argv); // Qt requires an instance of QApplication
QQmlEngine *engine = new QQmlEngine;
QString projectPath = "/Users/user/full/path/to/your/project"; // I'm on a Mac, but replace
// with the appropriate path to your project
// QQmlComponent component(engine, "MyItem.qml"); // this didn't work for me and
// set component.status() to QQmlComponent::Error
QQmlComponent component(engine, projectPath + "/qml/MyItem.qml"); // use full path
qDebug() << "Status:" << component.status();
if (component.status() == QQmlComponent::Error)
qDebug() << "Errors:" << component.errors();
else if (component.status() != QQmlComponent::Ready)
{
qDebug() << "Component is not ready!";
return 0;
}
QObject *object = component.create();
if (!object) { qDebug() << "Object creation failed!"; return 0; }
QQuickItem *item = qobject_cast<QQuickItem*>(object); // adding this didn't change much
// but this could be crucial
QVariant returnedValue;
QVariant msg = "Hello from C++";
bool success = QMetaObject::invokeMethod(item, "myQmlFunction", // replace `object` with `item`
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
if (success)
qDebug() << "QML function returned:" << returnedValue.toString();
else
qDebug() << "QMetaObject::invokeMethod returned false";
delete object;
return 0;
}
Output
The output I received on a successful build, with a successful object creation was
Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"
I haven't yet checked whether the text changed in your Qml textbox
. (Didn't bother to. It'll require more changes to the C++ code and this answer is already long enough. I was also confident that nothing'll go wrong, so ¯_(ツ)_/¯).
Lé Non-Code
What if I don't want to use a raw file path?
If you're meh about using a raw file path (e.g. /Users/whoami/ugly/looking/path
) in
QString projectPath = "/Users/user/full/path/to/your/project";
You can add this to your .pro
file:
DEFINES += SOURCE_PATH=$$PWD
and set projectPath
to
QString projectPath = QT_STRINGIFY(SOURCE_PATH);
This idea was borrowed from a forum thread.
Assumptions
Throughout my answer, I have assumed that your project hierarchy resembles
/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml
The essential thing is that you use your full path to your qml item. If you do find another to reference it (maybe using QUrl
?) then do post a comment about it.
Further Reading
Check out the details section of the QQmlComponent
class and QQmlComponent::create
member function. Reading these led me to know which values to debug and what to look out for.
add a comment |
Lé Code
Qml
I'll assume that the qml code given actually belongs to MyItem.qml
instead of main.qml
.
Your Qml file generated an compile-time error. Functions should be placed inside an object, like so
// MyItem.qml
import QtQuick 2.0
Text {
id: textbox
text: "nothing"
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
}
I'm not sure how you were able to compile your project without generating an error, but I'm guessing either
- Your QtCreator/Qt version is not the same as mine (highly unlikely the cause); or
- You were try to making your code minimal and originally had a parent.
I'm sure you have a sufficient understanding about Qml so I'm not going to go deep into this.
C++
On the C++ side, I had to fiddle around with debug output to see what's wrong. Here's my main.cpp
:
// main.cpp
#include <QApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickItem>
int main(int argc, char *argv)
{
QApplication app(argc, argv); // Qt requires an instance of QApplication
QQmlEngine *engine = new QQmlEngine;
QString projectPath = "/Users/user/full/path/to/your/project"; // I'm on a Mac, but replace
// with the appropriate path to your project
// QQmlComponent component(engine, "MyItem.qml"); // this didn't work for me and
// set component.status() to QQmlComponent::Error
QQmlComponent component(engine, projectPath + "/qml/MyItem.qml"); // use full path
qDebug() << "Status:" << component.status();
if (component.status() == QQmlComponent::Error)
qDebug() << "Errors:" << component.errors();
else if (component.status() != QQmlComponent::Ready)
{
qDebug() << "Component is not ready!";
return 0;
}
QObject *object = component.create();
if (!object) { qDebug() << "Object creation failed!"; return 0; }
QQuickItem *item = qobject_cast<QQuickItem*>(object); // adding this didn't change much
// but this could be crucial
QVariant returnedValue;
QVariant msg = "Hello from C++";
bool success = QMetaObject::invokeMethod(item, "myQmlFunction", // replace `object` with `item`
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
if (success)
qDebug() << "QML function returned:" << returnedValue.toString();
else
qDebug() << "QMetaObject::invokeMethod returned false";
delete object;
return 0;
}
Output
The output I received on a successful build, with a successful object creation was
Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"
I haven't yet checked whether the text changed in your Qml textbox
. (Didn't bother to. It'll require more changes to the C++ code and this answer is already long enough. I was also confident that nothing'll go wrong, so ¯_(ツ)_/¯).
Lé Non-Code
What if I don't want to use a raw file path?
If you're meh about using a raw file path (e.g. /Users/whoami/ugly/looking/path
) in
QString projectPath = "/Users/user/full/path/to/your/project";
You can add this to your .pro
file:
DEFINES += SOURCE_PATH=$$PWD
and set projectPath
to
QString projectPath = QT_STRINGIFY(SOURCE_PATH);
This idea was borrowed from a forum thread.
Assumptions
Throughout my answer, I have assumed that your project hierarchy resembles
/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml
The essential thing is that you use your full path to your qml item. If you do find another to reference it (maybe using QUrl
?) then do post a comment about it.
Further Reading
Check out the details section of the QQmlComponent
class and QQmlComponent::create
member function. Reading these led me to know which values to debug and what to look out for.
add a comment |
Lé Code
Qml
I'll assume that the qml code given actually belongs to MyItem.qml
instead of main.qml
.
Your Qml file generated an compile-time error. Functions should be placed inside an object, like so
// MyItem.qml
import QtQuick 2.0
Text {
id: textbox
text: "nothing"
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
}
I'm not sure how you were able to compile your project without generating an error, but I'm guessing either
- Your QtCreator/Qt version is not the same as mine (highly unlikely the cause); or
- You were try to making your code minimal and originally had a parent.
I'm sure you have a sufficient understanding about Qml so I'm not going to go deep into this.
C++
On the C++ side, I had to fiddle around with debug output to see what's wrong. Here's my main.cpp
:
// main.cpp
#include <QApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickItem>
int main(int argc, char *argv)
{
QApplication app(argc, argv); // Qt requires an instance of QApplication
QQmlEngine *engine = new QQmlEngine;
QString projectPath = "/Users/user/full/path/to/your/project"; // I'm on a Mac, but replace
// with the appropriate path to your project
// QQmlComponent component(engine, "MyItem.qml"); // this didn't work for me and
// set component.status() to QQmlComponent::Error
QQmlComponent component(engine, projectPath + "/qml/MyItem.qml"); // use full path
qDebug() << "Status:" << component.status();
if (component.status() == QQmlComponent::Error)
qDebug() << "Errors:" << component.errors();
else if (component.status() != QQmlComponent::Ready)
{
qDebug() << "Component is not ready!";
return 0;
}
QObject *object = component.create();
if (!object) { qDebug() << "Object creation failed!"; return 0; }
QQuickItem *item = qobject_cast<QQuickItem*>(object); // adding this didn't change much
// but this could be crucial
QVariant returnedValue;
QVariant msg = "Hello from C++";
bool success = QMetaObject::invokeMethod(item, "myQmlFunction", // replace `object` with `item`
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
if (success)
qDebug() << "QML function returned:" << returnedValue.toString();
else
qDebug() << "QMetaObject::invokeMethod returned false";
delete object;
return 0;
}
Output
The output I received on a successful build, with a successful object creation was
Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"
I haven't yet checked whether the text changed in your Qml textbox
. (Didn't bother to. It'll require more changes to the C++ code and this answer is already long enough. I was also confident that nothing'll go wrong, so ¯_(ツ)_/¯).
Lé Non-Code
What if I don't want to use a raw file path?
If you're meh about using a raw file path (e.g. /Users/whoami/ugly/looking/path
) in
QString projectPath = "/Users/user/full/path/to/your/project";
You can add this to your .pro
file:
DEFINES += SOURCE_PATH=$$PWD
and set projectPath
to
QString projectPath = QT_STRINGIFY(SOURCE_PATH);
This idea was borrowed from a forum thread.
Assumptions
Throughout my answer, I have assumed that your project hierarchy resembles
/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml
The essential thing is that you use your full path to your qml item. If you do find another to reference it (maybe using QUrl
?) then do post a comment about it.
Further Reading
Check out the details section of the QQmlComponent
class and QQmlComponent::create
member function. Reading these led me to know which values to debug and what to look out for.
Lé Code
Qml
I'll assume that the qml code given actually belongs to MyItem.qml
instead of main.qml
.
Your Qml file generated an compile-time error. Functions should be placed inside an object, like so
// MyItem.qml
import QtQuick 2.0
Text {
id: textbox
text: "nothing"
function myQmlFunction(msg) {
console.log("Got message:", msg)
textbox.text = msg
return "some return value"
}
}
I'm not sure how you were able to compile your project without generating an error, but I'm guessing either
- Your QtCreator/Qt version is not the same as mine (highly unlikely the cause); or
- You were try to making your code minimal and originally had a parent.
I'm sure you have a sufficient understanding about Qml so I'm not going to go deep into this.
C++
On the C++ side, I had to fiddle around with debug output to see what's wrong. Here's my main.cpp
:
// main.cpp
#include <QApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickItem>
int main(int argc, char *argv)
{
QApplication app(argc, argv); // Qt requires an instance of QApplication
QQmlEngine *engine = new QQmlEngine;
QString projectPath = "/Users/user/full/path/to/your/project"; // I'm on a Mac, but replace
// with the appropriate path to your project
// QQmlComponent component(engine, "MyItem.qml"); // this didn't work for me and
// set component.status() to QQmlComponent::Error
QQmlComponent component(engine, projectPath + "/qml/MyItem.qml"); // use full path
qDebug() << "Status:" << component.status();
if (component.status() == QQmlComponent::Error)
qDebug() << "Errors:" << component.errors();
else if (component.status() != QQmlComponent::Ready)
{
qDebug() << "Component is not ready!";
return 0;
}
QObject *object = component.create();
if (!object) { qDebug() << "Object creation failed!"; return 0; }
QQuickItem *item = qobject_cast<QQuickItem*>(object); // adding this didn't change much
// but this could be crucial
QVariant returnedValue;
QVariant msg = "Hello from C++";
bool success = QMetaObject::invokeMethod(item, "myQmlFunction", // replace `object` with `item`
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
if (success)
qDebug() << "QML function returned:" << returnedValue.toString();
else
qDebug() << "QMetaObject::invokeMethod returned false";
delete object;
return 0;
}
Output
The output I received on a successful build, with a successful object creation was
Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"
I haven't yet checked whether the text changed in your Qml textbox
. (Didn't bother to. It'll require more changes to the C++ code and this answer is already long enough. I was also confident that nothing'll go wrong, so ¯_(ツ)_/¯).
Lé Non-Code
What if I don't want to use a raw file path?
If you're meh about using a raw file path (e.g. /Users/whoami/ugly/looking/path
) in
QString projectPath = "/Users/user/full/path/to/your/project";
You can add this to your .pro
file:
DEFINES += SOURCE_PATH=$$PWD
and set projectPath
to
QString projectPath = QT_STRINGIFY(SOURCE_PATH);
This idea was borrowed from a forum thread.
Assumptions
Throughout my answer, I have assumed that your project hierarchy resembles
/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml
The essential thing is that you use your full path to your qml item. If you do find another to reference it (maybe using QUrl
?) then do post a comment about it.
Further Reading
Check out the details section of the QQmlComponent
class and QQmlComponent::create
member function. Reading these led me to know which values to debug and what to look out for.
edited Nov 16 '18 at 10:00
answered Nov 16 '18 at 9:54
TrebuchetMSTrebuchetMS
3,10011125
3,10011125
add a comment |
add a comment |
Thanks for helping out,
I debugged it as well and the textbox.text was being overwritten with "Hello from C++" without the text in the window to be updated.
like eyllanesc suggested, I was creating a new engine object other than the already displayed window. (created elsewhere in the code)
after referencing the same object, the problem was solved.
add a comment |
Thanks for helping out,
I debugged it as well and the textbox.text was being overwritten with "Hello from C++" without the text in the window to be updated.
like eyllanesc suggested, I was creating a new engine object other than the already displayed window. (created elsewhere in the code)
after referencing the same object, the problem was solved.
add a comment |
Thanks for helping out,
I debugged it as well and the textbox.text was being overwritten with "Hello from C++" without the text in the window to be updated.
like eyllanesc suggested, I was creating a new engine object other than the already displayed window. (created elsewhere in the code)
after referencing the same object, the problem was solved.
Thanks for helping out,
I debugged it as well and the textbox.text was being overwritten with "Hello from C++" without the text in the window to be updated.
like eyllanesc suggested, I was creating a new engine object other than the already displayed window. (created elsewhere in the code)
after referencing the same object, the problem was solved.
answered Nov 16 '18 at 14:03
SparkskieSparkskie
11
11
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323350%2fqml-function-invoked-from-c-not-able-to-update-element%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
please improve your example and provide a Minimal, Complete, and Verifiable example, there are many things that are not defined and that are possibly causing the error. On the other hand you are creating a new item with component.create(); that may differ from the MyItem created elsewhere, even with your update your code does not make sense.
– eyllanesc
Nov 15 '18 at 16:08
1
main.qml or MyItem.qml????
– eyllanesc
Nov 15 '18 at 16:09
I see that you are creating a MyItem and instantly you are destroying it so it makes me presume that the visible MyItem is different and you have changed the text of another MyItem that you delete it instantly. every time you call component.create() you are creating another MyItem other than the one that is probably in your window. How do you create the window?
– eyllanesc
Nov 15 '18 at 16:12
On second thoughts, after posting my answer, sounds you're having an XY problem. @Sparkskie
– TrebuchetMS
Nov 16 '18 at 10:05