从C++调用的QML函数无法更新元素



我正在从C++调用QML函数。问题是QML函数在从C++调用时无法更新QML元素。下面是代码:

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"
}

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;

textbox元素只是一个常规文本,其中的文本保持为"nothing",而不是预期的"HellofromC++"。

关于如何解决这个问题,或者成功地将参数从C++传递到QML,有什么想法吗?

LéCode

Qml

我假设给出的qml代码实际上属于MyItem.qml,而不是main.qml

您的Qml文件生成了一个编译时错误。函数应该放在对象内部,就像一样

// 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"
}
}

我不确定你是如何在不产生错误的情况下编译你的项目的,但我猜

  1. 您的QtCreator/Qt版本与我的版本不同(原因极不可能(
  2. 您试图将代码最小化,并且最初有一个父级

我相信你对Qml有足够的了解,所以我不打算深入讨论。

C++

在C++方面,我不得不摆弄调试输出,看看出了什么问题。这是我的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;
}

输出

在一个成功的构建中,我收到的输出是

Status: QQmlComponent::Status(Ready)
Object: MyItem_QMLTYPE_0(0x7f8d4ae8b640)
qml: Got message: Hello from C++
QML function returned: "some return value"

我还没有检查您的Qmltextbox中的文本是否发生了更改。(没有麻烦。这需要对C++代码进行更多的更改,而且这个答案已经足够长了。我也相信不会出错,所以\_(ツ)_/(。


Lé非代码

如果我不想使用原始文件路径怎么办

如果您想在中使用原始文件路径(例如/Users/whoami/ugly/looking/path(

QString projectPath = "/Users/user/full/path/to/your/project";

您可以将其添加到.pro文件中:

DEFINES += SOURCE_PATH=$$PWD

并将projectPath设置为

QString projectPath = QT_STRINGIFY(SOURCE_PATH);

这个想法是从论坛帖子中借来的。


假设

在我的整个回答中,我假设您的项目层次结构类似于

/./
|- myProject.pro
|- main.cpp
|- qml/
|- MyItem.qml

最重要的是使用qml项目的完整路径。如果您确实找到另一个引用它(可能使用QUrl?(,则确实发布有关它的评论。


进一步阅读

查看QQmlComponent类和QQmlComponent::create成员函数的详细信息部分。阅读这些内容让我知道了要调试哪些值以及要注意什么。

感谢您的帮助,我也调试了它,textbox.text被"Hello from C++"覆盖,而窗口中没有要更新的文本。

正如eyllanesc所建议的,我正在创建一个新的引擎对象,而不是已经显示的窗口。(在代码的其他地方创建(

在引用了同一个对象之后,问题就解决了。

相关内容

  • 没有找到相关文章

最新更新