如何将不属于 QObject 的枚举暴露给 QJSEngine?

How to expose enum not owned by QObject to QJSEngine?

本文关键字:暴露 QJSEngine 枚举 不属于 QObject      更新时间:2023-10-16

我正在为我的软件编写脚本包装器,这样我就可以通过脚本控制我的软件。包装类的目的是将脚本接口与实际类分开,因为我可能不想公开类的所有信号和插槽。我正在使用Qt 5.13和QJSEngine。

我的问题是,根据我所阅读的内容和我的实验,似乎为了能够公开枚举,它需要在继承 QObject 并通过 newQObject((/setProperty(( 公开的类中。但是,我不想在下面的示例中公开类 Foo,但我仍然想向脚本环境公开枚举 Foo::Bar。我该怎么做?Q_ENUM似乎假设枚举在 QObject 中,并且 QObject 在脚本环境中公开(属性(。下面是我正在做的一个简短的例子(我希望能够从脚本环境中调用 FooWrapper::slot1((:

class Foo : public QObject
{
    Q_OBJECT
public:
    Foo(QJSEngine& engine)
    {
        auto wrapper = new FooWrapper(this, engine);
    }
    enum class Bar
    {
        VAL1,
        VAL2
    };
public slots:
    void slot1(Bar bar);
    void slot2();
};
class FooWrapper : public QObject
{
    Q_OBJECT
public:
    Foo(Foo& foo, QJSEngine& engine)
        : foo(&foo)
    {
        QJSValue obj = engine.newQObject(this);
        auto gObj = engine.globalObject();
        gObj.setProperty("foo", obj);
    }
public slots:
    void slot1(Bar bar)
    {
        foo->slot1(bar);
    }
private:
    Foo* foo;
};

好吧,对于 OP 的 Dago(对不起!万一其他人遇到这种情况...

一个选项与一般的 QML 相同,即可以从命名空间注册枚举和标志。使用 Q_ENUM_NS()Q_FLAG_NS()(对于标志,Q_DECLARE_FLAGS()调用保持不变,也Q_DECLARE_OPERATORS_FOR_FLAGS()命名空间外部,与类相同,如果需要的话(。

这里有我的相关答案: 如何从 QML 访问C++枚举?

但是对于纯JSEngine使用,只需将命名空间的QMetaObject设置为引擎中的属性就足够了......不需要qmlRegisterUncreatableMetaObject...的东西。

所以总结一下...

#include <QObject>  // required for the macros below
namespace MyNamespace
{
    Q_NAMESPACE        // required for meta object creation
    enum class Bar {
        VAL1,
        VAL2,
    };
    Q_ENUM_NS(Bar)     // register the enum in meta object data
}
// declare the enum's meta type (required if enum will be used in
// methods/functions exposed to JS. 
Q_DECLARE_METATYPE(MyNamespace::Bar)

稍后在某处的QJSEngine初始化例程中...

QJSEngine *jse = new QJSEngine();
...
// Register the namespace's meta object as a property of the global
// object (or any other object's property for that matter).
// The property name doesn't have to match the namespace name.
jse->globalObject().setProperty(
    "MyNamespace", 
    jse->newQMetaObject(&MyNamespace::staticMetaObject)
);

然后在 JS 环境中,枚举可用作命名空间本身的属性。

QJSValue v = jse->evaluate("MyNamespace.VAL2");  // v.toInt() == 1

或在脚本中...

console.log('>>', MyNamespace.VAL2);  // output: >> 1

另一种选择可能是将枚举保留在类中,并将类的QMetaObject注册为引擎的属性......只是不要将构造函数(或任何其他静态方法(标记为Q_INVOKABLE

HTH,
-Max

参考资料:
https://doc.qt.io/qt-6/qjsengine.html#newQMetaObject
https://doc.qt.io/qt-6/qobject.html#Q_NAMESPACE
https://doc.qt.io/qt-6/qobject.html#Q_ENUM_NS

找不到对注册命名空间元对象的直接引用,正如我刚才描述的那样...... 我向你保证它可以工作(并且有很多版本(。

在本节末尾,这里模糊地引用了它。 https://doc.qt.io/qt-5/qqmlengine.html#QML_ELEMENT

另一个更不相关(但可能很有趣(:https://doc.qt.io/qt-6/qqmlengine.html#QML_EXTENDED_NAMESPACE