[英]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());
}
}
感谢@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。
得到教训:
qmlRegisterType 和import Foo 1.0
的组合不起作用。 在研究了更多之后,即使使用 Q_OBJECT,我也遇到了类似的错误,这告诉我我的错误与 Q_GADGET 无关。 我会更多地研究它。
注意:似乎 Q_GADGET [和 Q_ENUM,就此而言] 是自动注册的,并且不需要 Q_DECLARE_METATYPE 宏,根据此Q_DECLARE_METATYPE(Type)链接。
我觉得你真的很亲近。 只是缺少了几件事:
Q_DECLARE_METATYPE
允许 QVariant 保存 Foo object:struct Foo
{
Q_GADGET
public:
Q_INVOKABLE static QString bar() { return QString("Invoked"); }
};
Q_DECLARE_METATYPE(Foo)
Foo foo;
engine.rootContext()->setContextProperty("Foo", QVariant::fromValue<Foo>(foo));
然后在 QML 中,调用Foo.bar()
工作正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.