folibis
folibis

Reputation: 12874

QML Repeater parentness

Let's say I have 2 types of custom elements — Parent and Child.

And there can be more than one Parent in the scene.

A simple scene looks like this:

Parent {
    Child {
        id: child1
    }
    Child {
        id: child2
    }
}

After the scene is loaded, I want to initialize all the Children in Parent class:

void InitializeChildren() {
    list = findChildren<Child*>(QString(),Qt::FindChildrenRecursively);
    foreach(Child * child,list) {
        InitChild(this,child);
}

But it fails with a more complicated scene:

Parent {
    Rectangle {
        Repeater {
            model: 10
            delegate: Child {
            }
        }
    }    
}

Just because the Repeater has no Child objects as children.

How can I get all Child's objects if I know exactly that they are nested children of the specified Parent?

Upvotes: 3

Views: 2128

Answers (2)

Christian Feldbacher
Christian Feldbacher

Reputation: 515

There was a change in Qt5 which makes using findChildren() for Repeater children not usable anymore. After having a look at qquickrepeater.cpp, it turns out that the Repeater calls QQuickItem::setParentItem() to the children delegates that get created. Thus, the original parents and children remain untouched, but the "visual" parent is the parent of the Repeater.

TLDR: Do not use findChildren() in Qt5 to browse through the item scene graph. Instead, use something like the following:

void getAllSearchTypes(QQuickItem *parent, QList<SearchType *> &list) {

 QList<QQuickItem *> children = parent->childItems();   
  foreach (QQuickItem *item, children) {
    SearchType *searchObject = dynamic_cast<SearchType *>(item);
    if (seachObject) list.append(searchObject);
    // call recursively and browse through the whole scene graph
    getAllSearchTypes(item, list);
 } 
}

And call the function like that:

QList<SearchType *> list;
getAllSearchTypes(rootItem, list);
// list now contains all objects of type SearchType, recursively searched children of rootItem

Replace SearchType with the C++ type you are looking for.

NOTE: the relevant change to findChildren(), is that you need to call childItems() and not children(). Ideally, there would be a template function in QQuickItem for example called findChildItems() in future Qt versions, which does the above recursive search internally.

Upvotes: 3

Kirween
Kirween

Reputation: 1538

Instead of parsing the repeater you can set the model in you c++ code:

Parent {
    Rectangle {
        Repeater {
            model: childModel
            delegate: Child {
                 Text { text: childValue }
            }
        }
    }    
}

In your c++:

QList<QObject*> m_childModel;
void InitializeChildren() {
    this->m_childModel.append(new Child("value 1"));
    this->m_childModel.append(new Child("value 2"));
    this->m_scene->rootContext()->setContextProperty("childModel", QVariant::fromValue(m_childModel));
}

you also need to do the setContextProperty before loading the root QML file.

And the Child declaration:

class Child : public QObject
{
    Q_OBJECT

public:
    Child(QString value) : m_value(value) {}
    Q_PROPERTY(QString  childValue    READ getChildValue  WRITE setChildValue    NOTIFY childValueUpdated)
    // Other properties... 

    QString getChildValue()    const { return m_value; }
    void setChildValue(const QString &value)
    {
        if (value == m_value)
            return;
        m_value = value;
        emit childValueUpdated();
    }

signals:
    void childValueUpdated();

private:
    QString m_value;

}

Upvotes: 0

Related Questions