我有以下函数,它返回一个 javascript 数组作为 QJSValue。但是当我从 QML 调用这个函数时,生成的对象始终是“未定义”。
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY (QJSValue test READ test NOTIFY testChanged)
public:
MyClass() {}
QJSValue test()
{
QJSEngine engine;
QJSValue l = engine.newArray(5);
for (int i = 0; i < 5; i++) {
l.setProperty(i, i);
}
return l;
}
static void RegisterTypes()
{
qmlRegisterUncreatableType<MyClass>("MyTypes", 1, 0, "MyClass", "Creation of MyClass type not supported");
}
Q_SIGNALS:
void testChanged();
}
int main() {
QQmlApplicationEngine engine;
MyClass mc;
MyClass::RegisterTypes();
engine.rootContext()->setContextProperty("myClass", &mc);
// ...
}
这几乎正是QJSValue 上的 Qt 文档中建议使用数组的方式。
例如以下按钮始终输出“未定义”:
Button {
onClicked: console.log(myClass.test)
}
回答您问题的重要部分写在本段落中。数组存储在创建它们的引擎的堆上。在你的情况下,你有两个独立的引擎。一个来自
QQmlApplicationEngine
,另一个是您在 test()
函数中创建的。两者都有一个堆并且彼此分离,这就是数组未定义的原因。基元不存储在堆上,这就是 return QJSValue(5)
在您的示例中起作用的原因。
要解决此问题,您可以将“主”引擎转发到您的
MyClass
并使用它来创建数组。
QQmlApplicationEngine engine;
MyClass mc(&engine);
MyClass::registerTypes();
engine.rootContext()->setContextProperty("myClass", &mc);
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QJSValue test READ test NOTIFY testChanged)
public:
MyClass(QQmlEngine *engine)
: m_engine(engine)
{}
QJSValue test()
{
QJSValue l = m_engine->newArray(5);
for (int i = 0; i < 5; i++) {
l.setProperty(i, i);
}
return l;
}
static void registerTypes()
{
qmlRegisterUncreatableType<MyClass>("MyTypes",
1,
0,
"MyClass",
"Creation of MyClass type not supported");
}
signals:
void testChanged();
private:
QQmlEngine *m_engine = nullptr;
};
在这里您可以找到完整的工作示例。