Joel Gibson
Joel Gibson

Reputation: 293

How to use Qt properties with custom classes?

So I'm starting to get the hang of Qt's MOC system in C++, and have been using the Q_PROPERTY macro and associated functionality to get introspection on Qt inbuilt types. However I can't seem to find a way of defining properties for custom types.

For example, in the following code, I can use metaObjects to identify, read and write with the variable A, which is a member of TestParent, with the use of Q_PROPERTY and the two corresponding functions. However attempting to register anything of the custom type Child gives me the error

QObject::QObject(const QObject&) is private within this context

I understand that this is because Child inherits from QObject, but I would like to use Qt's properties system within the Child class too, which requires inheritance from QObject. Is there a correct way of implementing this?

class Child : public QObject
{
  Q_OBJECT       //Q_OBJECT macro required here for the MOC to use introspection
public:
  explicit Child(QObject *parent = 0);
  ~Child();
};

class TestParent : public QObject
{
  Q_OBJECT
  Q_PROPERTY(int A  READ A WRITE setA)               //this works
  Q_PROPERTY(Child child READ child WRITE setChild)  //this doesn't

public:
  explicit TestParent(QObject *parent = 0);
  ~TestParent();

  void setA(int A) {_A = A;}
  int A() const {return _A;}

  void setChild(Child c) {_child = c;}
  Child child() const {return _child;}

private:
  int _A;
  Child _child;
};

The constructors and destructors both TestParent and Child are implemented blank methods in the .cpp file

Thanks.

Upvotes: 2

Views: 5105

Answers (2)

user4620747
user4620747

Reputation:

You need to implement assignment operator and copy constructor to use your Child property by-value (as in your code, not by-pointer from previous comment). If you'll use it by-pointer, don't forget to set parent to this property on creation (so you will not need directly destroy it)

So, this is example:

#pragma once

#include <QObject>

class Child : public QObject
{
    Q_OBJECT

public:
    Child() = default;
    Child(const Child &other, QObject *parent = nullptr)
        : QObject(parent)
    {
        Q_UNUSED(other);
    }

public:
    Child& operator =(const Child &other) {
        Q_UNUSED(other);
        return *this;
    }
};

class TestParent : public QObject
{
    Q_OBJECT

    Q_PROPERTY(int a  READ a WRITE setA NOTIFY aChanged)
    Q_PROPERTY(Child child READ child WRITE setChild NOTIFY childChanged)

public:
    TestParent() = default;

signals:
    void aChanged();
    void childChanged();

public:
    void setA(const int &a) { _a = a; }
    const int& a() const { return _a; }

    void setChild(Child c) { _child = c; }
    const Child& child() const { return _child; }

private:
    int _a;
    Child _child;
};

Upvotes: 0

Joel Gibson
Joel Gibson

Reputation: 293

Ah, got it now. Thanks Retired Ninja.

For others looking for this, it ends up being

class TestParent : public QObject
{
  Q_OBJECT
  Q_PROPERTY(Child * child READ child WRITE setChild)

public:
  explicit TestParent(QObject *parent = 0);
  ~TestParent();

  void setChild(Child *c) {_child = c;}
  Child * child() const {return _child;}

private:
  Child * _child;
};

But don't forget to initialise that pointer!

Upvotes: 1

Related Questions