[英]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.