簡體   English   中英

將 Q_GADGET 中的 Q_INVOKABLE 暴露給 QML

[英]Exposing Q_INVOKABLE in Q_GADGET to QML

我最初的目標是在 QML 中提供枚舉的名稱。 該名稱可以通過 QMetaEnum 和 QVariant 的 toString() 提供,在 QML 中都沒有。

Stack Overflow 上的文章展示了如何將 Q_INVOKABLE 添加到 QObject; 此方法可以實現上述任何一種方法來解決問題(並且此方法將是一個方便的解決方案,這些枚舉未在 Object 中聲明)。 但是,這些枚舉是使用 Q_ENUM_NS 定義的,它沒有位置/支持 Q_INVOKABLE AFAIK。

所以問題變成了:如何以最輕的方式使 QML 可以使用 C 函數或“靜態方法”?

我想避免使用基於 Q_OBJECT 的解決方案,因為不需要信號或 QObject 提供的大量開銷。 通過閱讀 doc.qt.io 和這里,答案似乎是 Q_GADGET 中的 Q_INVOKABLE。 在這里閱讀Q_GADGET狀態:

Q_GADGET 可以有 Q_ENUM、Q_PROPERTY 和 Q_INVOKABLE,但它們不能有信號或槽。

如何在 QML 中創建 Q_GADGET 結構的新實例? 顯示 Struct/Q_GADGET,但使用中間 object。

QML - Q_INVOKABLE 函數顯示對象內的 Q_INVOKABLE,但不顯示小工具。

QML 可以看到我的 Q_GADGET 但看不到 Q_OBJECT接近了,顯示了在 Struct 中定義多個 Q_PROPERTY 的代碼。 它還提到代碼工作正常,但沒有顯示 QML 或 main.cpp 代碼。 注意:不是作者的錯,因為他的目標是讓 QObject 工作,而不是 Struct。

我可以打開 go。 我無法找到一篇文章,顯示 Q_GADGET 中的Q_INVOKABLE 直接暴露在 QML 中而不依賴 QObject 有可能這樣做嗎? 如果是這樣,您會使用類似於下面的結構嗎?

    struct Foo
    {
        Q_GADGET
        public:
        Q_INVOKABLE static QString bar() { return QString("invoked"); }
    };

作為對@JarMan 的回應,我添加了一個帶有 main.cpp 和 main.qml 的 MRE。 我嘗試了各種 qmlRegister... 方法。 我不清楚需要使用哪些 qmlRegister... 方法來注冊 Struct(或者是否需要使用它們)。 engine.rootContext()->setContextProperty(...)適用於 object 實例,但會為 struct Foo 生成錯誤。
foo.h

#include <QQmlContext>

struct Foo
{
    Q_GADGET
    public:
    Q_INVOKABLE static QString bar() { return QString("Invoked"); }
};

主.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>


int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    Foo foo;
    qDebug() << "in main.cpp" << foo.bar();                  // works

    qmlRegisterType<Foo>("Foo", 1, 0, "Foo");                // error

    QQmlApplicationEngine engine;

  /*engine.rootContext()->setContextProperty("Foo", &foo);*/ // error

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);    

    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

import Foo 1.0

ApplicationWindow {
    visible: true
    height: 400
    width:  400
    
    Component.onCompleted: {
        console.log("In main.qml: "+Foo.bar());
    }
}

setContextProperty 的解決方案

感謝@JarMan 為 setContextProperty 提供解決方案: setContextProperty 現在可以工作(如下所述) - 它工作得很好。

    Foo foo;
    qDebug() << "in main.cpp" << foo.bar();                  // works

  //qmlRegisterType<Foo>("Foo", 1, 0, "Foo");                // error

    QQmlApplicationEngine engine;

    // works
    engine.rootContext()->setContextProperty("Foo", QVariant::fromValue<Foo>(foo));

對 main.cpp 的更改(上圖),在 main.qml 中注釋import Foo ,並將結構放置在專用的 header 文件中(如頂部所示)允許 MRE 編譯、運行和生成預期的 Z78E6221F6398FCE41. 所以這兩種方法之一有效:我可以通過 setContextProperty 公開 Q_INVOKABLE。
得到教訓:

  1. Q_GADGET [和 Q_OBJECT,就此而言] 如果它們沒有專用的 header 文件,它們往往會產生錯誤,並且
  2. 在 QVariant 中發送結構!

qmlRegisterType 和import Foo 1.0的組合不起作用。 在研究了更多之后,即使使用 Q_OBJECT,我也遇到了類似的錯誤,這告訴我我的錯誤與 Q_GADGET 無關。 我會更多地研究它。

注意:似乎 Q_GADGET [和 Q_ENUM,就此而言] 是自動注冊的,並且不需要 Q_DECLARE_METATYPE 宏,根據此Q_DECLARE_METATYPE(Type)鏈接。

我覺得你真的很親近。 只是缺少了幾件事:

  1. 使用Q_DECLARE_METATYPE允許 QVariant 保存 Foo object:
struct Foo
{
    Q_GADGET
public:
    Q_INVOKABLE static QString bar() { return QString("Invoked"); }
};
Q_DECLARE_METATYPE(Foo)
  1. 將您的小工具作為 QVariant 發送到 QML:
    Foo foo;
    engine.rootContext()->setContextProperty("Foo", QVariant::fromValue<Foo>(foo));

然后在 QML 中,調用Foo.bar()工作正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM