Nulik
Nulik

Reputation: 7400

How to align QML components in a delegate

I want to align my list of phone numbers with one field ("name") on the left side and another field ("phone") on the right side. However when trying to bind anchor properties inside the delegate, it says that the delegate object is not a parent of the ListView component. How do I reach other components from the delegate?

This is my QML code:

import QtQuick 2.7
import QtQuick.Controls 2.0

Item {
    id: enclosing_area
    width: 500
    height: 300
    ListModel {
        id: dataModel
        ListElement {
            name: "John Smith"
            phone: "1111-1111"
        }
        ListElement {
            name: "Peter Poter"
            phone: "2222-2222"
        }
        ListElement {
            name: "Anna Lasalle"
            phone: "3333-3333"
        }
    }

    ListView {
        id: list
        width: enclosing_area.width
        height: enclosing_area.height
        model: dataModel
        delegate: Rectangle  {
            width: enclosing_area.width
            border.color: "red"
            Label {
                text: name
                anchors.left: list.left
            }
            Label {
                text: phone
                anchors.right: list.right
            }
        }
   }
}

qmlscene produces the following errors:

file:///LViewTest.qml:36:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.
file:///LViewTest.qml:32:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.
file:///LViewTest.qml:36:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.
file:///LViewTest.qml:32:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.
file:///LViewTest.qml:36:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.
file:///LViewTest.qml:32:13: QML Label: Cannot anchor to an item that isn't a parent or sibling.

Lines 32 and 32 are "anchors.left" and "anchors.right" statements. How do I bind to properties in another objects from the delegate in my case?

Upvotes: 2

Views: 5915

Answers (2)

derM
derM

Reputation: 13711

At first:

It would be convention to call your enclosing_area root instead.
Secondly, if you don't anchor to a sibling, don't use the id of the object you want to anchor to, but use parent.

This prevents you from having your errors, as - what you are trying to do - is not anchoring to the parent of the Labels, but to their parents parent.
The parent of the Label would be the Rectangle in your delegate.

ListView {
    id: list  // <- This is not the parent of the Labels, but of the delegateRectangle
    width: enclosing_area.width     // works
    height: enclosing_area.height   // works
    // anchors.fill: parent         <- would do the same, more flexible, and only one line.
    model: dataModel
    delegate: Rectangle  {
        id: delegateRectangle // <--- This is the parent of the two Labels
        width: enclosing_area.width
        height: 30 // <- a heightis necessary. 
                   // As the objects are repositioned you need to set it explicitely
                   // and can't use anchoring. You could use the
                   // implicit height of it's children, to make it nice
        border.color: "red"
        Label {
            text: name
            anchors.left: delegateRectangle.left // this would work instead.
                                                 // list.left woudl try to anchor to the 'grandparent'
        }
        Label {
            text: phone
            anchors.right: parent.right // this would be the reccomended way.
                                        // Would also anchor to delegateRectangle
        }
    }
}

Why should you prefer to anchor to parent rather than your parents id?
The object will (almost) always have a visual parent, but this visual parent could change. Either because you add an extra layer in code, later - or even during runtime, by reparenting it. So you would always need to update the anchors as well.
Therefore, anchoring to parent resolves one easy error.

Upvotes: 4

selbie
selbie

Reputation: 104589

Take advantage of anchors instead of trying to hardcode the size of a child element to match its parent. That will enable you to use anchors all the way down. (Similarly, use anchor margins instead of hardcoded x,y values). You get a lot of other benefits with anchors.

    ListView {
        id: list
        anchors.fill: parent
        model: dataModel
        delegate: Rectangle  {
            anchors.left: parent.left
            anchors.right: parent.right
            height: 50       // you need a height otherwise all rows are on the same line
            border.color: "red"
            Label {
                text: name
                anchors.left: parent.left
            }
            Label {
                text: phone
                anchors.right: parent.right
            }
        }
   }
}

Upvotes: 2

Related Questions