ListView的itemAtIndex不返回索引处的项目

问题描述

假设我们有一个模型和两个视图。两个视图使用相同的模型。第二个视图中的项目必须与第一个视图中的相应项目具有相同的宽度。项目之间的宽度不是恒定的。两个视图之间的项目具有相同的索引。

下面的代码产生两个矩形的系列,其索引为文本。 view2中的矩形更窄:

import QtQuick 2.15

Rectangle {
    ListView {
        id: view1
        y: 0
        height: 50
        width: parent.width

        model: ts_model
        delegate: Rectangle {
            width: 60
            height: 50
            color: "black"
            Text {
                text: index
                color: "white"
            }
        }

        orientation: Qt.Horizontal
        layoutDirection: "LeftToRight"
        spacing: 5
    }

    ListView {
        id: view2
        y: 100
        height: 50
        width: parent.width

        model: ts_model
        delegate: Rectangle {
            color: "yellow"
            width: 50
            height: 50
            Text {
                text: index
            }
        }

        orientation: Qt.Horizontal
        layoutDirection: "LeftToRight"
        spacing: 5
    }
}

enter image description here

让我们尝试将view1中的矩形宽度绑定到view2中的矩形。我希望能够使用view1.itemAtIndex(index)语法做到这一点:

ListView {
        id: view2
        y: 100
        height: 50
        width: parent.width

        model: ts_model
        delegate: Rectangle {
            color: "yellow"
            width: view1.itemAtIndex(index).width
            height: 50
            Text {
                text: index
            }
        }
(... some more code ...)

不幸的是,这不起作用-我得到TypeError: Cannot read property 'width' of null,有趣的是仅对某些项目失败了:

enter image description here

我确认:

  1. 两个视图都显示相同数量的元素(相同的模型,没有过滤)
  2. 两者的索引都从0开始,一直上升到模型中的元素数减去1(如两张图片所示)
  3. 两个索引都是整数
  4. view1view2是同一个父母的孩子,我验证了他们在通过id寻址时可以看到对方

为什么不起作用?

解决方法

这个答案是错误的。它仅适用于所有元素均可见的列表。当代表进入/超出范围时,这会崩溃。

但是,要回答最初的问题-itemAtIndex始终不返回项目的原因是由于构造顺序,即调用该方法时index处的项目未完全构造。

正如JarMan所建议的,问题与view1的子代构造有关。通过一个简单的测试就可以看出这一点。我添加了一条消息来标识创建矩形的顺序:

// view1
delegate: Rectangle {
            width: 60
            height: 50
            color: "black"
            Text {
                text: index
                color: "white"
                Component.onCompleted: console.log("Rect1 " + index + " completed")
            }
        }
// view2
delegate: Rectangle {
                color: "yellow"
                width: view1.itemAtIndex(index).width
                height: 50
                Text {
                    text: index
                }
                Component.onCompleted: console.log("Rect2 " + index + " completed")
            }

哪个会产生以下输出:

qml: Rect2 0 completed
qml: Rect1 0 completed
file:///...: TypeError: Cannot read property 'width' of null
qml: Rect1 1 completed
qml: Rect1 2 completed
qml: Rect1 3 completed
qml: Rect1 4 completed
qml: Rect2 1 completed
qml: Rect2 2 completed
qml: Rect2 3 completed
qml: Rect2 4 completed
qml: Rect2 5 completed
qml: Rect2 6 completed
qml: Rect2 7 completed
qml: Rect2 8 completed
qml: Rect2 9 completed
file:///...: TypeError: Cannot read property 'width' of null
file:///...: TypeError: Cannot read property 'width' of null
file:///...: TypeError: Cannot read property 'width' of null
file:///...: TypeError: Cannot read property 'width' of null
file:///...: TypeError: Cannot read property 'width' of null
qml: Rect1 5 completed
qml: Rect1 6 completed
qml: Rect1 7 completed

很明显,view2中没有正确创建的矩形是在view1对应的矩形可用之前创建的。

创建动态对象here

一种解决方法是:1)将第二个视图保存到单独的QML文件中; 2)在完成根项后将其创建为子视图:

view2's QML file

import QtQuick 2.0

ListView {
    id: view2
    y: 100
    height: 50
    width: parent.width

    model: ts_model
    delegate: Rectangle {
        color: "yellow"
        width: view1.itemAtIndex(index).width
        height: 50
        Text {
            text: index
        }
    }

    orientation: Qt.Horizontal
    layoutDirection: "LeftToRight"
    spacing: 5
}

main file

import QtQuick 2.15

Rectangle {
    id: rect
    Component.onCompleted: {
        Qt.createComponent("view2.qml").createObject(rect)
    }

    ListView {
        id: view1
        y: 0
        height: 50
        width: parent.width

        model: ts_model
        delegate: Rectangle {
            width: 60
            height: 50
            color: "black"
            Text {
                text: index
                color: "white"
            }
        }

        orientation: Qt.Horizontal
        layoutDirection: "LeftToRight"
        spacing: 5
    }
}

哪个会产生所需的结果: correct result