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

问题描述 投票:0回答:10
class StyleClass : public QObject {
public:
    typedef enum
        {
            STYLE_RADIAL,
            STYLE_ENVELOPE,
            STYLE_FILLED
        }  Style;

    Style m_style;
    //...
};

.h文件中有上述代码。 如何通过QML访问上述枚举?

c++ qt qml qtquick2
10个回答
63
投票

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

风格.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

main.cpp:

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

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

    //...

    StyleClass::declareQML();

    //...

    return a.exec();
}

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

    //...
}

55
投票

从 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
}

注册命名空间(例如,在创建 Qml 视图/上下文之前在 main() 中):

qmlRegisterUncreatableMetaObject(
  MyNamespace::staticMetaObject, // meta object created by Q_NAMESPACE macro
  "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
);

在 QML 文件中使用它:

import QtQuick 2.0
import my.namespace 1.0

Item {
    Component.onCompleted: console.log(MyNamespace.STYLE_RADIAL)
}

参考资料:

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


29
投票

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

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

这会起作用:

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

这不:

enum EnStyle
{
    styleRADIAL,
    styleENVELOPE,
    styleFILLED
};
Q_ENUMS(EnStyle)

您在编译时不会收到任何类型的错误,它们只是被 QML 引擎忽略。


14
投票

我找到了一个非常好的在 QML 中使用 C++ 类中的 ENUM 的解决方案,在这里: 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)
};

2) 如何使用 QML 引擎将类注册为“不可创建类型”:
(这就是使这个解决方案变得漂亮和独特的部分。)

// main.cpp

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

使用

qmlRegisterUncreatableType
可防止在 QML 中实例化
StatusClass
。如果用户尝试实例化此类,将会记录一条警告:

qrc:/main.qml:16 Not creatable as it is an enum type.

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.
    }
}

重要提示:
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
...

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

// main.qml

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

    // Wrong
    console.log(statusClassObj.Ready); // undefined
}
...

人们容易犯这个错误的原因是因为Qt Creator 的自动完成功能将 ENUM 列为选项,无论是在使用类名还是上下文属性进行引用时。所以遇到这种情况请务必小心。


8
投票

从 Qt 5.10 版开始,Qt 还支持 QML 定义的枚举类型。作为air-dex 基于 C++ 的答案的替代方案,您现在还可以使用 QML 创建枚举类型:

样式.qml:

import QtQuick 2.0

QtObject {
  enum EnStyle {
    STYLE_RADIAL,
    STYLE_ENVELOPE,
    STYLE_FILLED
  }
}

如果您只想在 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")
  }
}

请参阅此处,了解基于 QML 的枚举类型的另一个使用示例。


7
投票

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

class DataEmitter : public QObject
{
    Q_OBJECT

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

...

emit setStyle(StyleClass.STYLE_RADIAL);

QML-部分:

Connections {
    target: dataEmitter
    onSetStyle: {
         myObject.style=style
    }
}

这段代码会生成运行时错误,如下所示:

IndicatorArea.qml:124: Error: Cannot assign [undefined] to int

要使此代码正常工作,您必须额外注册 Qt 元对象类型:

qRegisterMetaType<StyleClass::EnStyle>("StyleClass.EnStyle");

更多详细信息写在这里:https://webhamster.ru/mytetrashare/index/mtb0/1535044840rbtgvfmjys(rus)


3
投票

使用

moc
宏让
Q_ENUMS
了解您的枚举,如 docs 中所述。您必须在使用枚举之前注册“拥有”枚举的类,如文档中所述。

Ashif 的引用块仅在枚举是全局枚举或由非

QObject

 派生类拥有时才有效。


2
投票

对于 Qt 6.2 及更高版本,将宏 QML_ELEMENT

Q_ENUM()
(不是已弃用的 
Q_ENUMS()
)添加到类中。因为它是一个 QObject,所以它也应该已经有 
Q_OBJECT
,以便将其注册到 Qt MOC 系统。

class StyleClass : public QObject { Q_OBJECT // Let the MOC know about this QObject QML_ELEMENT // Make this object available to QML public: typedef enum { STYLE_RADIAL, STYLE_ENVELOPE, STYLE_FILLED } Style; Style m_style; Q_ENUM(Style) // Make this enum available to QML //... };
Qt 中的创新意味着这些宏就足够了,并且 

不再需要单独手动注册类或枚举。

在 QML 中,您可以通过

{ClassName}.{EnumValue}

 访问枚举,而不引用枚举名称。例如
StyleClass.STYLE_RADIAL

    


0
投票
我的变体(为了在名称空间不可用时向后兼容,请使用手动预定义宏 ENABLE_USE_ENUM_NAMESPACES):

// enum.h #pragma once #include <QObject> #ifndef ENABLE_USE_ENUM_NAMESPACES class TaskTypeEnums : public QObject { Q_OBJECT Q_ENUMS(TaskTypeEnum) public: explicit TaskTypeEnums(QObject *parent = nullptr): QObject(parent) {} #else namespace TaskTypeEnums { Q_NAMESPACE #endif enum TaskTypeEnum { TaskConnectDev, TaskDisconnectDev, TaskPingDev, TaskResetDev, TaskTakeControlDev, TaskSetAkaModDev, TaskFirmwareUpdDev, TaskConnectDevs, TaskDisconnectAll, TaskMainTestSot, TaskMainTestBA, }; #ifndef ENABLE_USE_ENUM_NAMESPACES }; #else Q_ENUM_NS(TaskTypeEnum) } #endif // ---------------------------------------------------------------------------- // fragment from main.cpp //... #ifdef ENABLE_USE_ENUM_NAMESPACES qmlRegisterUncreatableMetaObject(TaskTypeEnums::staticMetaObject, "Vip.Enums.Tasks", 1, 0, "Tasks", ""); #else qmlRegisterType<TaskTypeEnums>("Vip.Enums.Tasks", 1, 0, "Tasks"); #endif //...
    

0
投票
//main.cpp registered c++ enum qmlRegisterType<LampManager>("LampManager",1,0, "LampManager"); //LampManager.h enum LAMP_LAMPFAULTCODE{ FAULTCODE_TRACTORLEFTFRONT, FAULTCODE_TRACTOREAR, FAULTCODE_TRAILERLEF, FAULTCODE_TRACTORIGRIGHTFON, FAULTCODE_TRACTORRIGHTREAR, }; Q_ENUM(LAMP_LAMPFAULTCODE) //main.qml use c++ enuem property var closefaultcodearray:[ LampManager.FAULTCODE_TRACTORLEFTFRONT, LampManager.FAULTCODE_TRACTOREAR, LampManager.FAULTCODE_TRAILERLEFT, LampManager.FAULTCODE_TRACTORIGRIGHTFONT, LampManager.FAULTCODE_TRACTORRIGHTREAR,]
    
© www.soinside.com 2019 - 2024. All rights reserved.