1

My code:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480

    Column {
        Row {
            Repeater {
                id: rectRepeater
                model: 3
                Rectangle {
                    width: 30
                    height: 30
                    color: "red"
                    radius: 10
                }
            }
        }
        Row {
            Repeater {
                model: 3
                Text {
                    text: rectRepeater.itemAt(0).width;
                }
            }
        }
    }
}

I get this error message:

TypeError: Cannot read property 'width' of null

I found this post saying that the solution is to use Component.onCompleted like this (just inserting a Component.onCompleted handler inside the Text object):

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480

    Column {
        Row {
            Repeater {
                id: rectRepeater
                model: 3
                Rectangle {
                    width: 30
                    height: 30
                    color: "red"
                    radius: 10
                }
            }
        }
        Row {
            Repeater {
                model: 3
                Text {
                    Component.onCompleted: {
                        text: rectRepeater.itemAt(0).width;
                    }
                }
            }
        }
    }
}

But this fails with the same error.

Any idea?

2 Answers 2

2

rectRepeater items is not exit when you call itemAt(0).

You should call itemAt when rectRepeater is instantiated.

Window {
    visible: true
    width: 640
    height: 480
    Column {
        Row {
            Repeater {
                id: rectRepeater
                model: 3
                Rectangle {
                    width: 30
                    height: 30
                    color: "red"
                    radius: 10
                }

            }
        }
        Row {
            Repeater {
                id: textrep
                model: 3
                Text {
                    }
            }
        }
        Component.onCompleted: {
            //Here all object are instantiated
            for (var i = 0; i< textrep.count; i++){
                textrep.itemAt(i).text = rectRepeater.itemAt(0).width
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, this works. So the key is to wait for onCompleted. But my own code waits for that signal as well! (see the second code snippet in my question.) So what's the difference?
In your code onCompleted signal applies to Text component only. So it emmit when text component is instantiated. In my code onCompleted applied to Column component and it emmit when column component and all him childs is instantiated.
2

I would go for a conditional binding instead

Text {
    text: rectRepeater.count > 0 ? rectRepeater.itemAt(0).width : 0;
}

Once the rectRepeater has actually created at least one delegate, the value from that delegate is read. That works even if the rectRepeater's model becomes empty again at some point or if the item at index 0 changes its width

7 Comments

Cool, thanks! This is in some ways more elegant than the onCompleted solution. You wrote some of the reasons, and also it lets me have the binding code right in the element that it affects, which is very nice. A disadvantage is that it's somewhat verbose (especially as bindings don't support multi-statement binding functions) and it's hard to understand its purpose, necessitating a comment. But all in all, it's the solution I'll use. Note that Konstantin T.'s answer also permits doing a dynamic binding for the width, by assigning a Qt.binding(...) expression.
Hm, I just tested multi-statement binding functions and it turns out they work! This makes your solution an even more attractive one.
Speculation, did not verify: This might end up setting the text 3 times (in this example), as the repeaters count increases from 0 to 3. Here it is basically irrelevant, but in some other cases it might be heavy enough to matter.
The binding expression will be evaluated again when the count changes, but the setter of the text property will realize that there was no change, so no unecessary update request for the visualization or any binding that uses that text property as one of its inputs
Not sure what you mean with mulit-statement bindings, but a binding expression is basically a function and can be arbitratily complex (not that this would necessarily be a good idea). You could also define a function in rectRepeater that does that and use that function as the binding expression: text: rectRepeater.firstRectWidth()
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.