繁体   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