Qt QML ListView contentHeight行为

时间:2014-09-09 13:05:26

标签: qt listview qt4 qml qt5

将QML ListView元素与其section属性结合使用时,我遇到了一个非常具体的问题。

我使用的是Qt 4.8.6,但是当我在Qt 5.3.1中尝试这个时,我也有同样的问题。

通过简单地将import语句更改为

,也可以在旧版本的Qt中运行以下代码
  

导入QtQuick 1.0(适用于< Qt 4.7.4)

  

导入QtQuick 1.1(对于> = Qt 4.7.4)

这是一个独立的用例来演示我的问题:

import QtQuick 2.2

Rectangle {
    width: 800
    height: 800
    color: "black"

    property int pageNumber: 1
    property int totalPages: Math.ceil(animalListView.contentHeight/animalListView.height)

    Text {
        x: 2
        y: 90
        color: "Orange"
        text: "Expected height: " + (animalListView.count*70 + (50*10))
        font.pixelSize: 28
    }

    Text {
        x: 2
        y: 0
        color: "Orange"
        text: "Actual ContentHeight: " + animalListView.contentHeight
        font.pixelSize: 28
    }

    Text {
        x: 2
        y: 30
        color: "Orange"
        text: "Actual ChildrenRectHeight: " + animalListView.childrenRect.height
        font.pixelSize: 28
    }

    Text {
        x: 2
        y: 60
        color: "Orange"
        text: "Total model items (minus sections): " + animalListView.count
        font.pixelSize: 28
    }

    Rectangle {
        id: boundingRect
        width: 640
        height: 500
        x: 20
        y: 200
        radius: 10
        border.width: 1
        border.color: "green"
        color: "transparent"

        // The delegate for each section header
        Component {
            id: sectionHeaderDelegate
            Rectangle {
                width: parent.width
                height: 50 // this is the problem                
                color: "transparent"                

                Text {
                    anchors.left: parent.left
                    id: headerText
                    text: section
                    color: "red"
                }

                Rectangle {
                    anchors.fill: parent
                    border.color: "purple"                    
                    border.width: 1    
                    color: "transparent"
                }
            }
        }

        ListModel {
             id: animalsModel
             ListElement { name: "1Parrot"; size: "Small" }
             ListElement { name: "2Guinea pig"; size: "Small" }
             ListElement { name: "3Dog"; size: "Medium" }
             ListElement { name: "4Cat"; size: "Medium" }
             ListElement { name: "5Elephant"; size: "Medium" }
             ListElement { name: "6Parrot"; size: "Small" }
             ListElement { name: "7Guinea pig"; size: "Small" }
             ListElement { name: "8Dog"; size: "Medium" }
             ListElement { name: "9Cat"; size: "Medium" }
             ListElement { name: "10Elephant"; size: "Large" }
             ListElement { name: "11Parrot"; size: "Large" }
             ListElement { name: "12Guinea pig"; size: "Large" }
             ListElement { name: "13Dog"; size: "Large" }
             ListElement { name: "14Cat"; size: "Medium" }
             ListElement { name: "15Elephant"; size: "Large" }
             ListElement { name: "16Parrot"; size: "Small" }
             ListElement { name: "17Guinea pig"; size: "Small" }
             ListElement { name: "18Dog"; size: "Medium" }
             ListElement { name: "19Cat"; size: "Medium" }
             ListElement { name: "20Elephant"; size: "Large" }
        }

        ListView {
            id: animalListView
            anchors.fill: parent
            anchors.margins: 10
            clip: true
            interactive: true
            flickableDirection: Flickable.VerticalFlick
            boundsBehavior: Flickable.StopAtBounds
            model: animalsModel

            delegate: Item {
                width: parent.width
                height: 70
                    Text {
                        text: name
                        color: "green"
                    }

                    Rectangle {
                        anchors.fill: parent
                        border.color: "yellow"                    
                        border.width: 1    
                        color: "transparent"
                    }
                }

            section.property: "size"
            section.criteria: ViewSection.FullString
            section.delegate: sectionHeaderDelegate
        }
    }

    Rectangle {
        anchors.top: boundingRect.top
        anchors.left: boundingRect.right
        anchors.leftMargin: 20        
        width: 40
        height: 40
        color: "blue"

         MouseArea {
             anchors.fill: parent
             onClicked: {
                if (pageNumber > 1) {
                    animalListView.contentY -= animalListView.height;
                    animalListView.returnToBounds();
                    --pageNumber;
                }             
             }
         }

        enabled: (!animalListView.atYBeginning)
        visible: !(animalListView.atYBeginning && animalListView.atYEnd)

        Text {
            anchors.centerIn: parent
            font.family: "Wingdings 3"
            font.pixelSize: 40
            text: "Ç" // Up arrow
        }
    }

    Text {
        visible: totalPages > 1
        anchors.left: boundingRect.right
        anchors.verticalCenter: boundingRect.verticalCenter
        width: 100
        height: 20
        font.pixelSize: 18
        horizontalAlignment: Text.AlignHCenter
        color: "red"
        text: qsTr("%1 of %2").arg(pageNumber).arg(totalPages)
    }

    Rectangle {
        anchors.bottom: boundingRect.bottom
        anchors.left: boundingRect.right
        anchors.leftMargin: 20
        width: 40
        height: 40
        color: "orange"

         MouseArea {
             anchors.fill: parent
             onClicked: {
                if (pageNumber < totalPages) {
                    animalListView.contentY += animalListView.height;
                    ++pageNumber;
                }
             }
         }

        enabled: (!animalListView.atYEnd)
        visible: !(animalListView.atYBeginning && animalListView.atYEnd)

        Text {
            anchors.centerIn: parent
            font.family: "Wingdings 3"
            font.pixelSize: 40
            text: "È" // Down arrow
        }
    }

}

我使用ListView显示动物模型列表,按其大小分类。为了在视图中实现此分类,我使用ListView的 section.property section.critiria section.delegate 属性作为在上面给出的代码中实现。

注意:请忽略我向ListView提供的模型未排序的事实,我知道这将在ListView中创建许多重复的类别条目。这不是重点。 )

当模型数超过ListView的可见区域时,我使用属性 totalPages 来计算有多少完整的ListView页面用于导航。向上箭头和向下箭头按钮分别按ListView的高度递减和递增ListView的 content.Y

问题是ListView的 contentHeight 不会保持静态,它会动态更改并导致我的 totalPages 属性计算不正确。

有趣的是,当且仅当我为 sectionHeaderDelegate 矩形设置了高度时才会出现这种情况。如果我注释掉高度语句(高度:50),ListView的 contentHeight 保持静态,正如预期的那样 - 缺点是节标题/类别现在位于模型文本的顶部,根本没用。

所以我的问题是,为什么QML ListView元素的contentHeight会动态地改变当且仅当我使用了一个高度被设置为非零值的部分委托?

另外,我在ListView中留下了以下属性用于测试目的,ListView应该与向上/向下箭头一起使用:

          interactive: true
          flickableDirection: Flickable.VerticalFlick
          boundsBehavior: Flickable.StopAtBounds

3 个答案:

答案 0 :(得分:4)

我知道这很古老,但无论如何我都会在这里回答,因为我一直在寻找解决方案;

如果物品的高度固定,您只需通过公式设置值即可动态设置容器的高度:

MyContainerWithListItems {
height: MyModel.items.length * height
}

如果你有可变高度的物品,那将更加困难;解决方案可能是让onChange事件触发一个函数,该函数遍历您的项目并手动累加高度。

答案 1 :(得分:3)

这是因为ListView正在通过当前可见的项目估计其contentHeight。检查当您的部分无法分组时会发生什么。 ListView避免实例化每个项目,因此它不知道不可见内容的正确大小。 Look at this thread.

答案 2 :(得分:0)

声明一个存储列表视图高度的全局属性:

property int propertyListViewHeight:0

将 ListView 放在一个透明项中,其高度等于该全局属性 propertyListViewHeight

Item {
    id: rectangleEntities
    width: parent.width
    height: propertyListViewHeight
    ListView {
        id: listViewEntities
        anchors.fill: parent
        model: entityModel
        delegate: listDelegate
        focus: true
        boundsBehavior: Flickable.StopAtBounds
        highlightMoveDuration: 1000
        highlightMoveVelocity: 1000
    }
    
}

在您的委托定义中添加 onCompleted 信号,然后将列表中每个项目的高度添加到您的全局属性 propertyListViewHeight

组件{ id:listDelegate 矩形 { 编号:容器 宽度:父级宽度

        Component.onCompleted: {
            propertyListViewHeight += height
        }
        
    }
}