简体   繁体   English

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

[英]QML function invoked from C++ not able to update element

I am invoking a QML function from C++.我正在从 C++ 调用 QML 函数。 Issue is the QML function cannot update a QML element when invoked from C++.问题是 QML 函数在从 C++ 调用时无法更新 QML 元素。 below is code:下面是代码:

In main.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"
}

In main.cpp :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++". textbox 元素只是一个普通文本,其中的文本保持“无”,而不是预期的“Hello from C++”。

Any ideas on how to solve this issue or in successfully passing arguments from C++ to QML?关于如何解决这个问题或成功地将参数从 C++ 传递到 QML 的任何想法?

Lé Code乐码

Qml质量管理器

I'll assume that the qml code given actually belongs to MyItem.qml instead of main.qml .我假设给出的MyItem.qml代码实际上属于MyItem.qml而不是main.qml

Your Qml file generated an compile-time error.您的 Qml 文件生成了编译时错误。 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我不确定你是如何编译你的项目而不产生错误的,但我猜要么

  1. Your QtCreator/Qt version is not the same as mine (highly unlikely the cause);您的 QtCreator/Qt 版本与我的不同(原因极不可能); or或者
  2. 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.我相信您对 Qml 有足够的了解,所以我不打算深入探讨。

C++ C++

On the C++ side, I had to fiddle around with debug output to see what's wrong.在 C++ 方面,我不得不摆弄调试输出以查看出了什么问题。 Here's my main.cpp :这是我的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 .我还没有检查你的 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 ¯\\_(ツ)_/¯). (没有打扰。它需要对 C++ 代码进行更多更改,这个答案已经足够长了。我也有信心不会出错,所以¯\\_(ツ)_/¯)。


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 (eg /Users/whoami/ugly/looking/path ) in如果你是如何使用原始文件路径(例如MEH /Users/whoami/ugly/looking/path中)

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

You can add this to your .pro file:您可以将其添加到您的.pro文件中:

DEFINES += SOURCE_PATH=$$PWD

and set projectPath to并将projectPath设置为

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.最重要的是你使用你的 qml 项目的完整路径。 If you do find another to reference it (maybe using QUrl ?) then do post a comment about it.如果您确实找到了另一个引用它(也许使用QUrl ?),那么发表评论。


Further Reading进一步阅读

Check out the details section of the QQmlComponent class and QQmlComponent::create member function .查看QQmlComponent类和QQmlComponent::create成员函数详细信息部分 Reading these led me to know which values to debug and what to look out for.阅读这些让我知道要调试哪些值以及要注意什么。

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.感谢您的帮助,我也调试了它,并且 textbox.text 被“Hello from C++”覆盖,而窗口中的文本没有更新。

like eyllanesc suggested, I was creating a new engine object other than the already displayed window.就像 eyllanesc 建议的那样,我正在创建一个新的引擎对象,而不是已经显示的窗口。 (created elsewhere in the code) (在代码的其他地方创建)

after referencing the same object, the problem was solved.引用同一个对象后,问题就解决了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM