Object::property ( const char * name ) const returning empty QVariant

749 Views Asked by At

My class has enum property, i wish to access this property using QObject*. When calling QVariant QObject::property ( const char * name ) const return value is empty QVariant of enum type.

Consider the following code:

/* Interface class */
class IFoo
{
Q_GADGET
public:
  Q_ENUMS(ColorType)

  typedef enum
  {
    COLOR_RED = 0,
    COLOR_BLUE
  } ColorType;

  virtual QString Name(void) const = 0;
};
Q_DECLARE_METATYPE(IFoo::ColorType)

class Foo
  : public IFoo
{
Q_OBJECT
public:
  Foo(void) 
  {
    qint32 typeId = qRegisterMetaType<IFoo::ColorType>("ColorType");
    qRegisterMetaTypeStreamOperators<int>(IFoo::ColorType);
  }
  virtual QString Name(void) const { return _name; }

  void SetColor(ColorType color) { _color = color; }
  ColorType Color(void) const { return _color; }
  QString ColorString(void) const { return _color == IFoo::COLOR_RED ? "Red" : "Blue"; }

  Q_PROPERTY(IFoo::ColorType Color READ Color WRITE SetColor)
  Q_PROPERTY(QString ColorString READ ColorString)

private:
  ColorType _color;
  QString _name;
};

int main (int argc, char **argv) {
  QCoreApplication app(argc, argv);

  Foo f;
  f.SetColor(IFoo::COLOR_RED);

  qDebug() << f.property("Color"); // Returns QVariant(IFoo::ColorType, ) 
  qDebug() << f.property("ColorString"); // Returns QString(Red)
}

Why does property return empty QVariant value? String wrapper property works as it should.

2

There are 2 best solutions below

1
Marek R On

It looks like that moc tool is unable to generate strings for respective values. IMO problem is typedef. Try simple enum inside of class:

enum ColorType {
  COLOR_RED = 0,
  COLOR_BLUE
};

Or typedef with enum keyword:

typedef enum {
  COLOR_RED = 0,
  COLOR_BLUE
} ColorType;

I'm pretty sure that missing enum keyword confuses the moc tool.

0
Alejandro Exojo On

There were a few mistakes on the code that prevent it from compiling:

  1. Using Q_OBJECT without inheriting from QObject.
  2. qRegisterMetaType is not needed if you use Q_ENUM (which I used to replace Q_ENUMS, which is the old version, deprecated in 5.5).
  3. qRegisterMetaTypeStreamOperators was being passed an int as template argument instead of the type to register, and the argument to the function (not template argument) should be a string, which is optional anyway; but not a type.

Full source:

#include <QtCore> // Just for the test. Use more fine grained includes.

/* Interface class */
class IFoo
{
Q_GADGET
public:

  enum ColorType
  {
    COLOR_RED = 0,
    COLOR_BLUE
  };
  Q_ENUM(ColorType)

  virtual QString Name(void) const = 0;
};

class Foo : public QObject, public IFoo
{
Q_OBJECT
public:
  Foo(void) 
  {
    qRegisterMetaTypeStreamOperators<IFoo::ColorType>();
  }
  virtual QString Name(void) const { return _name; }

  void SetColor(ColorType color) { _color = color; }
  ColorType Color(void) const { return _color; }
  QString ColorString(void) const { return _color == IFoo::COLOR_RED ? "Red" : "Blue"; }

  Q_PROPERTY(IFoo::ColorType Color READ Color WRITE SetColor)
  Q_PROPERTY(QString ColorString READ ColorString)

private:
  ColorType _color;
  QString _name;
};

int main (int argc, char **argv) {
  QCoreApplication app(argc, argv);

  Foo f;
  f.SetColor(IFoo::COLOR_RED);

  qDebug() << f.property("Color"); // Returns QVariant(IFoo::ColorType, ) 
  qDebug() << f.property("ColorString"); // Returns QString(Red)
  // Now returns:
  // QVariant(IFoo::ColorType, "COLOR_RED")
  // QVariant(QString, "Red")
}

#include "main.moc"