iHowell
iHowell

Reputation: 2447

How can I have a abstract class pointer as a Q_PROPERTY?

I am trying to use instances of an abstract class as a property in one of my extended QQuickItems. I have a basic class, like this:

class VizFactory : public QQuickItem
{
    Q_OBJECT;
    Q_PROPERTY(VisualizationOptions * options READ options WRITE setOptions);

   private:
    VisualizationOptions * m_visualizationOptions;

   public:
    VizFactory(QQuickItem * parent = 0) : QQuickItem(parent) {}
    ~VizFactory() {}

    VisualizationOptions * options() const;
    void setOptions(VisualizationOptions * options);
};

Where VisualizationOptions is an abstract class that extends some other classes, like LayoutOptions and FooOptions:

class VisualizationOptions : public QObject
{
    Q_OBJECT

   public:
    VisualizationOptions(QObject * parent = 0) : QObject(parent) {}
    virtual std::string getVisualizationName() const = 0;
};

I register everything in my main file using:

qmlRegisterUncreatableType<VisualizationOptions>("Wormhole", 1, 0, "VisualizationOptions",
                                                 QString("Cannot create abstract class VisualizationOptions"));
qmlRegisterType<LayoutOptions>("Wormhole", 1, 0, "LayoutOptions");
qmlRegisterType<FooOptions>("Wormhole", 1, 0, "FooOptions");

Then, I try to use it in a qml file by putting in:

VizFactory {
    options: LayoutOptions {
        type: "row"

        FooOptions {}
        LayoutOptions {
            type: "col"
            FooOptions {}
            FooOptions {}
        }
    }
}

But, the error I'm getting is from the qml file on the line defining options, saying: "Cannot assign to non-existent default property". Why is this happening? Am I not registering the types correctly? Am I instantiating the objects in QML incorrectly?

Upvotes: 3

Views: 472

Answers (1)

eyllanesc
eyllanesc

Reputation: 244003

The problem is not caused by the abstract class but because the QObjects do not have childItems, unlike the QQuickItem that does have that property.

The same thing you could see if you use QtObject:

QtObject{
    QtObject{

    }
}

message:

Cannot assign to non-existent default property

So there are 3 possible solutions:

  • Make VisualizationOptions inherit from QQuickItem and so you can have children.

  • Do not assign children, for example with your code should work the following:

    VizFactory{
        options: LayoutOptions{
        }
    }
    
  • use QQmlListproperty

I will show an example using the third method:

class VisualizationOptions: public QObject{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<VisualizationOptions> childOptions READ options)
public:
    using QObject::QObject;
    virtual std::string getVisualizationName() const = 0;
    QQmlListProperty<VisualizationOptions> options(){
        return QQmlListProperty<VisualizationOptions>(this, this,
                                                      &VisualizationOptions::appendOption,
                                                      &VisualizationOptions::optionCount,
                                                      &VisualizationOptions::option,
                                                      &VisualizationOptions::clearOptions);
    }
    void appendOption(VisualizationOptions* p) {
        m_childsoptions.append(p);
    }
    int optionCount() const{
        return m_childsoptions.count();
    }
    VisualizationOptions *option(int index) const{
        return m_childsoptions.at(index);
    }
    void clearOptions() {
        m_childsoptions.clear();
    }
private:
    static void appendOption(QQmlListProperty<VisualizationOptions>* list, VisualizationOptions* p) {
        reinterpret_cast<VisualizationOptions* >(list->data)->appendOption(p);
    }
    static void clearOptions(QQmlListProperty<VisualizationOptions>* list) {
        reinterpret_cast<VisualizationOptions* >(list->data)->clearOptions();
    }
    static VisualizationOptions* option(QQmlListProperty<VisualizationOptions>* list, int i) {
        return reinterpret_cast< VisualizationOptions* >(list->data)->option(i);
    }
    static int optionCount(QQmlListProperty<VisualizationOptions>* list) {
        return reinterpret_cast< VisualizationOptions* >(list->data)->optionCount();
    }
    QVector<VisualizationOptions *> m_childsoptions;
};

*.qml

VizFactory{
    options:
        LayoutOptions{
        type: "row"
        childOptions: [
            FooOptions{},
            LayoutOptions{
                type: "col"
                childOptions: [
                    FooOptions {},
                    FooOptions {}
                ]
            }
        ]
    }
}

You can find the complete code in the following link.

Upvotes: 3

Related Questions