如何从QML访问C++枚举?

Aqu*_*irl 36 c++ qt qml qtquick2

class StyleClass : public QObject {
public:
    typedef enum
        {
            STYLE_RADIAL,
            STYLE_ENVELOPE,
            STYLE_FILLED
        }  Style;

    Style m_style;
    //...
};
Run Code Online (Sandbox Code Playgroud)

.h文件包含上面的代码.如何通过QML访问上面的枚举?

air*_*dex 41

您可以将枚举包装在一个派生自QObject的类中(并且您公开给QML):

style.hpp:

#ifndef STYLE_HPP
#define STYLE_HPP

#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    // Qt 4
    #include <QDeclarativeEngine>
#else
    // Qt 5
    #include <QQmlEngine>
#endif

// Required derivation from QObject
class StyleClass : public QObject
{
    Q_OBJECT

    public:
        // Default constructor, required for classes you expose to QML.
        StyleClass() : QObject() {}

        enum EnStyle
        {
            STYLE_RADIAL,
            STYLE_ENVELOPE,
            STYLE_FILLED
        };
        Q_ENUMS(EnStyle)

        // Do not forget to declare your class to the QML system.
        static void declareQML() {
            qmlRegisterType<StyleClass>("MyQMLEnums", 13, 37, "Style");
        }
};

#endif    // STYLE_HPP
Run Code Online (Sandbox Code Playgroud)

main.cpp中:

#include <QApplication>
#include "style.hpp"

int main (int argc, char ** argv) {
    QApplication a(argc, argv);

    //...

    StyleClass::declareQML();

    //...

    return a.exec();
}
Run Code Online (Sandbox Code Playgroud)

QML代码:

import MyQMLEnums 13.37
import QtQuick 2.0    // Or 1.1 depending on your Qt version

Item {
    id: myitem

    //...

    property int item_style: Style.STYLE_RADIAL

    //...
}
Run Code Online (Sandbox Code Playgroud)

  • 想知道是否有一种方法可以在QObject派生类中找到枚举(例如,在UI下没有Qt依赖项的软件层中)。 (2认同)
  • @DavidJ从Qt v5.8开始,您可以对名称空间中的枚举执行此操作。请参阅[下面的答案](/sf/answers/3367475121/)。 (2认同)

Max*_*rno 22

从Qt 5.8开始,您可以通过以下方式公开枚举namespace:

定义命名空间和枚举:

#include <QObject>

namespace MyNamespace
{
    Q_NAMESPACE         // required for meta object creation
    enum EnStyle {
        STYLE_RADIAL,
        STYLE_ENVELOPE,
        STYLE_FILLED
    };
    Q_ENUM_NS(EnStyle)  // register the enum in meta object data
}
Run Code Online (Sandbox Code Playgroud)

在创建Qml View/Context之前注册命名空间(例如,在main()中):

qmlRegisterUncreatableMetaObject(
  MyNamespace::staticMetaObject, // static meta object
  "my.namespace",                // import statement (can be any string)
  1, 0,                          // major and minor version of the import
  "MyNamespace",                 // name in QML (does not have to match C++ name)
  "Error: only enums"            // error in case someone tries to create a MyNamespace object
);
Run Code Online (Sandbox Code Playgroud)

在QML文件中使用它:

import QtQuick 2.0
import my.namespace 1.0

Item {
    Component.onCompleted: console.log(MyNamespace.STYLE_RADIAL)
}
Run Code Online (Sandbox Code Playgroud)

参考文献:

https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/

http://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableMetaObject

http://doc.qt.io/qt-5/qobject.html#Q_ENUM_NS

  • 如果您像我一样想知道,“staticMetaObject”是通过“Q_NAMESPACE”宏添加到您的命名空间的对象。 (3认同)

Ric*_*832 20

其他信息(在Qt 5.5之前未记录):

您的枚举值名称必须以大写字母开头.

这将有效:

enum EnStyle
{
    STYLE_RADIAL,
    STYLE_ENVELOPE,
    STYLE_FILLED
};
Q_ENUMS(EnStyle)
Run Code Online (Sandbox Code Playgroud)

这不是:

enum EnStyle
{
    styleRADIAL,
    styleENVELOPE,
    styleFILLED
};
Q_ENUMS(EnStyle)
Run Code Online (Sandbox Code Playgroud)

你不会在编译时遇到任何错误,它们会被QML引擎忽略.

  • @big_gie我将这位尊敬的绅士称为"截至发布时",以及我当时制作的Qt错误报告.现在记录了_beause_我采取了一些措施将其添加到文档中. (5认同)

zeF*_*ree 10

我找到了一个非常好的解决方案,用于在 QML 中使用来自 C++ 类的 ENUM,这里: Enums in Qt QML - qml.guide。这篇文章太好了,我觉得有必要在这里与 SO 社区分享。恕我直言,应该始终进行归因,因此添加了帖子的链接。

该帖子主要描述了:

1) 如何在 Qt/C++ 中创建 ENUM 类型:

// statusclass.h

#include <QObject>

class StatusClass
{
    Q_GADGET
public:
    explicit StatusClass();

    enum Value {
        Null,
        Ready,
        Loading,
        Error
    };
    Q_ENUM(Value)
};
Run Code Online (Sandbox Code Playgroud)

2)如何使用 QML 引擎将类注册为“不可创建的类型”:(
这是使该解决方案美观而独特的部分。)

// main.cpp

...
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<StatusClass>("qml.guide", 1, 0, "StatusClass",
                                        "Not creatable as it is an enum type.");
...
Run Code Online (Sandbox Code Playgroud)

使用qmlRegisterUncreatableType防止StatusClass在 QML 中的实例化。如果用户尝试实例化此类,则会记录警告:

qrc:/main.qml:16 Not creatable as it is an enum type.
Run Code Online (Sandbox Code Playgroud)

3)最后,如何在QML文件中使用ENUM:

// main.qml

import QtQuick 2.9
import QtQuick.Window 2.2

import qml.guide 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Component.onCompleted: {
        console.log(StatusClass.Ready); // <--- Here's how to use the ENUM.
    }
}
Run Code Online (Sandbox Code Playgroud)

重要说明:
应该通过使用类名引用它来使用 ENUM,就像这样StatusClass.Ready。如果在 QML 中也使用相同的类作为上下文属性......

// main.cpp

...
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<StatusClass>("qml.guide", 1, 0, "StatusClass",
                                        "Not creatable as it is an enum type.");

StatusClass statusClassObj; // Named such (perhaps poorly) for the sake of clarity in the example.
engine.rootContext()->setContextProperty("statusClassObj", &statusClassObj); // <--- like this
...
Run Code Online (Sandbox Code Playgroud)

...然后,有时人们会不小心将 ENUM 与上下文属性而不是类名一起使用。

// main.qml

...
Component.onCompleted: {
    // Correct
    console.log(StatusClass.Ready);    // 1

    // Wrong
    console.log(statusClassObj.Ready); // undefined
}
...
Run Code Online (Sandbox Code Playgroud)

人们倾向于犯这个错误的原因是因为Qt Creator 的自动完成功能将 ENUM 作为选项列出,无论是在使用类名还是上下文属性进行引用时。因此,在这种情况下,请谨慎行事。


GDe*_*evT 6

自Qt版本5.10起,Qt还支持QML定义的枚举类型.作为air-dex基于C++的回答的替代方法,您现在还可以使用QML创建枚举类型:

Style.qml:

import QtQuick 2.0

QtObject {
  enum EnStyle {
    STYLE_RADIAL,
    STYLE_ENVELOPE,
    STYLE_FILLED
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您只打算在QML代码中使用枚举,则此解决方案要简单得多.您可以使用qml中的Style类型访问上面的枚举,例如:

import VPlayApps 1.0
import QtQuick 2.9

App {

  property int enStyle: Style.EnStyle.STYLE_RADIAL

  Component.onCompleted: {
    if(enStyle === Style.EnStyle.STYLE_ENVELOPE)
      console.log("ENVELOPE")
    else
      console.log("NOT ENVELOPE")
  }
}
Run Code Online (Sandbox Code Playgroud)

有关基于QML的枚举类型的另一个用法示例,请参见此处.

  • 有什么办法可以在 C++ 中使用这些枚举吗? (2认同)

Xin*_*rea 6

无法启用所有这些解决方案,使用此枚举类作为信号/插槽的参数。这段代码可以编译,但在 QML 中不起作用:

class DataEmitter : public QObject
{
    Q_OBJECT

public:
    ...
signals:
    void setStyle(StyleClass::EnStyle style);
}

...

emit setStyle(StyleClass.STYLE_RADIAL);
Run Code Online (Sandbox Code Playgroud)

QML-部分:

Connections {
    target: dataEmitter
    onSetStyle: {
         myObject.style=style
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码生成运行时错误,如下所示:

IndicatorArea.qml:124: Error: Cannot assign [undefined] to int
Run Code Online (Sandbox Code Playgroud)

对于此代码工作,您必须附加注册表 Qt 元对象类型:

qRegisterMetaType<StyleClass::EnStyle>("StyleClass.EnStyle");
Run Code Online (Sandbox Code Playgroud)

更多细节写在这里:https ://webhamster.ru/mytetrashare/index/mtb0/1535044840rbtgvfmjys(俄罗斯)