0

我一直在尝试实现一些我认为应该非常简单的东西,但是遇到了问题。简而言之,我有一个包含一些 的类,其中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,我能想到的一切都很明显,没有任何变化。

4

2 回答 2

0

我试图复制你的源代码,我得到true了所有这些情况。请看一下:

这是EnumHolder.h,它定义了两个命名空间YoYo并分别YaYo包含枚举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中的枚举,它还定义了一个包含 3 个类型属性的调用,并且:FoodTypeEmbeddedQObjectFoodYoYo::FruitYaYo::VegetableEmbedded::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()or Q_DECLARE_META_TYPE。它只是按原样工作。

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

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

于 2020-12-22T06:07:22.863 回答
0

我相信,为了让您的元类型系统enum能够识别您Qt,它需要在 aQ_OBJECT或 a中声明Q_GADGET。如果你不想让它成为你的类的一部分(出于可理解的原因,如可重用性等),你可以声明一个带有Q_GADGET宏的单独结构,然后你可以在enum那里定义你的。底线是,如果您希望您的类型能够被Qt的元类型系统识别,但又不想将其设为 a QObject,则可以通过将其设为Q_GADGET. Q_OBJECT和之间的区别在于Q_GADGET,小工具不能有信号和插槽。

所以,它看起来像这样:

#include <QObject>

namespace Test_SameFile {    

struct EnumHolder {
private:
  Q_GADGET
public:

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

}

你可以试试看它是否有效。

于 2020-12-22T00:09:15.490 回答