枚举属性不被认可

时间:2020-12-21 23:55:11

标签: c++ qt enums qproperty qmetaobject

我一直在尝试实现一些我认为应该非常简单的东西,但我遇到了问题。简而言之,我有一个包含一些 Q_Properties 的类,其中一些我想成为命名空间级别的 enum 值。我的问题是,如果我将 enum 及其 namespace 移动到单独的文件中,QProperty 系统无法识别该属性是 enum 值。

这是一个精简版的说明:

一个文件包含一个带有枚举的命名空间以及我试图与枚举一起使用的类:

#ifndef ENUMPROPERTYTEST_H
#define ENUMPROPERTYTEST_H

#include <QObject>
#include "enumTest.h" //contains the other namespace and enum I want to use

namespace Test_SameFile {
Q_NAMESPACE

enum NSEnum_SameFile {
    A1,
    A2,
    A3
};
Q_ENUM_NS(NSEnum_SameFile)

}

class EnumPropertyTest : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int INT1 MEMBER myInt)
    //this enum is declared in the same file and works as expected
    Q_PROPERTY(Test_SameFile::NSEnum_SameFile ENUMVAL1 MEMBER a)
    //this enum is declared in a separate header file and does not
    Q_PROPERTY(Test_DiffFile::NSEnum_DiffFile ENUMVAL2 MEMBER g)

public:
    explicit EnumPropertyTest() : QObject() {}
    ~EnumPropertyTest() {}

private:
    int myInt = 5;
    Test_SameFile::NSEnum_SameFile a = Test_SameFile::A2;
    Test_DiffFile::NSEnum_DiffFile g = Test_DiffFile::T2;
};

#endif // ENUMPROPERTYTEST_H

我的头文件包含另一个命名空间和枚举:

#ifndef ENUMTEST_H
#define ENUMTEST_H

#include <QObject>

namespace Test_DiffFile {
Q_NAMESPACE

enum NSEnum_DiffFile {
    T1,
    T2,
    T3
};
Q_ENUM_NS(NSEnum_DiffFile)

}

#endif // ENUMTEST_H

我的主要内容:

#include <QObject>
#include <QMetaProperty>
#include <QDebug>

#include "enumpropertytest.h"

int main()
{
    auto id1 = qRegisterMetaType<Test_SameFile::NSEnum_SameFile>();
    auto id2 = qRegisterMetaType<Test_DiffFile::NSEnum_DiffFile>();
    auto e1 = QMetaEnum::fromType<Test_SameFile::NSEnum_SameFile>();
    qDebug() << "e1 id: " << id1 << ", valid:" << e1.isValid() << ", scope : " << e1.scope();

    auto e2 = QMetaEnum::fromType<Test_DiffFile::NSEnum_DiffFile>();
    qDebug() << "e2 id: " << id2 << ", valid:" << e2.isValid() << ", scope : " << e2.scope();

    EnumPropertyTest t;

    auto mo = t.metaObject();

    for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
        QString propName = mo->property(i).name();
        auto prop = mo->property(i);
        qDebug() << "Property: " << propName << "is an enum: " << prop.isEnumType();
    }

    return 0;
}

当我运行这个程序时,它输出以下内容:

e1 id:  1024 , valid: true , scope :  Test_SameFile
e2 id:  1025 , valid: true , scope :  Test_DiffFile
Property:  "INT1" is an enum:  false
Property:  "ENUMVAL1" is an enum:  true
Property:  "ENUMVAL2" is an enum:  false

如您所见,在与类相同的文件中声明的枚举在属性系统中按预期工作,但在头文件中声明的枚举未被识别为枚举。我该如何解决这个问题?我删除了构建文件夹,重新运行 qmake,我能想到的所有明显的东西都没有改变。

2 个答案:

答案 0 :(得分:0)

我相信为了让您的 enumQt 的元类型系统识别,它需要在 Q_OBJECTQ_GADGET 中声明。如果您不想将其作为类的一部分(出于可理解的原因,例如可重用性等),您可以声明一个单独的结构,其中包含 Q_GADGET 宏,然后您可以定义您的 enum那里。最重要的是,如果您希望 Qt 的元类型系统可以识别您的类型,但又不想将其设为 QObject,则只需将其设为 {{ 1}}。 Q_GADGETQ_OBJECT 之间的区别在于小工具不能有信号和槽。

所以,它看起来像这样:

Q_GADGET

你可以试试看是否有效。

答案 1 :(得分:0)

我尝试复制您的源代码,但我得到了所有这些案例的 true。请看:

这是 EnumHolder.h,它定义了两个命名空间 YoYoYaYo,分别包含枚举 FruitVegetable

#ifndef ENUMHOLDER_H
#define ENUMHOLDER_H

#include <QMetaProperty>

namespace YoYo {
Q_NAMESPACE

enum Fruit {
  Apple,
  Pear,
  Watermelon,
};
Q_ENUM_NS(Fruit)

}  // namespace YoYo

namespace YaYo {
Q_NAMESPACE
enum Vegetable {
  Broccoli,
  Tomato,
  Lettuce,
};
Q_ENUM_NS(Vegetable)
}  // namespace YaYo

#endif // ENUMHOLDER_H

这是Food.h,它定义了命名空间FoodType中的枚举Embedded,它还定义了一个名为QObject的{​​{1}},它包含3个类型的属性FoodYoYo::FruitYaYo::Vegetable

Embedded::FoodType

这是我的#ifndef FOOD_H #define FOOD_H #include <QMetaProperty> #include <QObject> #include "EnumHolder.h" namespace Embedded { Q_NAMESPACE enum FoodType { Food1, Food2, Food3, }; Q_ENUM_NS(FoodType) } // namespace Embedded class Food : public QObject { Q_OBJECT Q_PROPERTY(YoYo::Fruit fruit MEMBER _fruit) Q_PROPERTY(YaYo::Vegetable vegetable MEMBER _vegetable) Q_PROPERTY(Embedded::FoodType foodType MEMBER _foodType) private: YoYo::Fruit _fruit; YaYo::Vegetable _vegetable; Embedded::FoodType _foodType; }; #endif // FOOD_H

main.cpp

这是我的输出:

int main(int argc, char *argv[]) {
  QCoreApplication app(argc, argv);
  Food food;
  auto mo = food.metaObject();

  for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) {
    auto property = mo->property(i);
    qDebug() << property.name() << " is an enum: " << property.isEnumType();
  }

  return app.exec();
}

此外,我没有使用 fruit is an enum: true vegetable is an enum: true foodType is an enum: true qRegisterMetaType()。它只是按照现在的方式工作。

我想说的另一个注意事项是它可以作为概念证明,但这通常不是一个好主意,因为除非有需要,否则通常不想在代码中定义太多名称空间.在这里感觉就像将枚举放在单独的文件中一样,您必须定义一个包含 Q_DECLARE_META_TYPE 宏的新命名空间。我尝试重用相同的命名空间并在不同的头文件中定义另一个枚举,但出现 MOC 错误。对于给定的命名空间,您显然只能使用一次 Q_NAMESPACE。如果您的枚举顶部没有它,则不能使用 Q_NAMESPACE,因为您会收到另一个错误。

因此,拥有一个头文件可能是一个好主意,您将在其中定义命名空间中的所有枚举,这样您将仅对该命名空间使用一次 Q_ENUM_NS 并将所有这些枚举添加到 {{1} } 的元对象系统。