【问题标题】:Qml: ScrollView containing a ListView does not adjust ScrollBar handleQml:包含 ListView 的 ScrollView 不调整 ScrollBar 句柄
【发布时间】:2020-02-06 18:00:17
【问题描述】:

我正在尝试根据需要将垂直滚动条添加到 ListView。有人告诉我,最好的方法是将 ListView 放在 ScrollView 中,而不是在 ListView 中插入滚动条(如this question),因为这样可以提高 GPU 的效率。

我插入了它,如下例所示 - 但无论我尝试什么,如果滚动条显示,它的手柄总是占据整个高度,当然不会移动。

我希望你可以看看我的示例并给我一个建议,为什么滚动条不能正常显示。
代码中有 cmets 解释我做了什么以及为什么。

import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4

Item
{
    readonly property int parentWidth: 280
    readonly property int parentMaxHeight: 400

    // Main reason for doing this - the items are custom objects and
    // their width does not automatically adjust for having the scroll bar or not
    // But also, to set scroll bars because Qt.ScrollBarAsNeeded makes them not show
    property bool scrollBarVisible: myListView.contentHeight > myListView.height

    width: parentWidth
    height: parentMaxHeight

    Rectangle
    {
        id: myMenuRect

        anchors.rightMargin: 2
        anchors.leftMargin: 2
        anchors.bottomMargin: 4
        anchors.topMargin: 4

        width: parentWidth
        height: myListView.height
        radius: 10
        z: 2

        color: "red"   // Adding this to show why the height of the rectangle must match the listview
    }

    ScrollView
    {
        id: myScrollView
        parent: myMenuRect
        anchors.fill: parent

        anchors.topMargin: 5
        anchors.bottomMargin: 5
        anchors.rightMargin: 5

        frameVisible: false

        // I have tried to set implicitHeight in many different ways,
        // no matter what I do the scroll bar handle occupies the enire bar and doesn't move

        // The Qt.ScrollBarAsNeeded didn't work... so I did this
        verticalScrollBarPolicy: scrollBarVisible ? Qt.ScrollBarAlwaysOn : Qt.ScrollBarAlwaysOff

    // Adding colors on scrollbar to show which part is showing     
    style: ScrollViewStyle
    {
        handle: Rectangle
        {
            implicitWidth: 10
            implicitHeight: 2
            radius: 10
            anchors.leftMargin: 1
            anchors.left: parent.left
            color: "yellow"
        }

        scrollBarBackground: Rectangle
        {
            implicitWidth: 12
            anchors.right: parent.right
            color: "green"
        }
    }

    ListView
    {
        id: myListView
        parent: myScrollView
        model: wifiComboListModel

        focus: true
        clip: true
        interactive: false

        width: parent.width

        // I am trying to tell my view to take the minimum space it needs that is below 
        // a certain height. Ignore the "myListView." prefixes here, I know they are not needed but 
        // make it easier to move this outside if needed
        height: (myListView.contentHeight > 0 ?
                     (myListView.contentHeight < parentMaxHeight ?
                          myListView.contentHeight : parentMaxHeight) : 0)

        // I made this as simple as possible, without affecting "quality"
        delegate: Text
        {
            text: _comboBoxText
            height: 70
            width: parent.width - 20
        }
    }

    ListModel
    {
        id: wifiComboListModel
    }

    // I want to populate my model from outside, not be static. Not sure if this affects the bars
    function populateComboBoxListModel()
    {
        wifiComboListModel.clear();
        for (var itemIndex = 0; itemIndex < listItems.length; itemIndex++)
        {
            wifiComboListModel.append
                ({
                    _id: itemIndex,
                    _comboBoxText: listItems[itemIndex]
                });
        }
    }

    Component.onCompleted:
    {
        populateComboBoxListModel();
    }

    property var listItems: [
            "This",
            "annoying",
            "list",
            "view",
            "does",
            "not behave the way",
            "I expect.",
            "I",
            "tried many",
            "things,",
            "now I am",
            "begging for your",
            "help",
            "."
    ]
}

【问题讨论】:

    标签: qt listview qml scrollview


    【解决方案1】:

    您在 myMenuRect 中有一个高度绑定循环。这是因为 myMenuRect 取决于列表视图的高度,反之亦然。修复后似乎可以正常工作:

    import QtQuick 2.0 
    import QtQuick.Controls 1.4
    
    ApplicationWindow
    {
        readonly property int parentWidth: 280
        readonly property int parentMaxHeight: 400
        visible: true
    
        // Main reason for doing this - the items are custom objects and
        // their width does not automatically adjust for having the scroll bar or not
        // But also, to set scroll bars because Qt.ScrollBarAsNeeded makes them not show
        property bool scrollBarVisible: myListView.contentHeight > myListView.height
    
        width: parentWidth
        height: parentMaxHeight
    
        Rectangle
        {
            id: myMenuRect
    
            anchors.rightMargin: 2
            anchors.leftMargin: 2
            anchors.bottomMargin: 4
            anchors.topMargin: 4
    
            width: parentWidth
            height: parentMaxHeight
            radius: 10
            z: 2
        }
    
        ScrollView
        {
            id: myScrollView
            parent: myMenuRect
            anchors.fill: parent
    
            anchors.topMargin: 5
            anchors.bottomMargin: 5
            anchors.rightMargin: 5
    
            frameVisible: false
    
            // I have tried to set implicitHeight in many different ways,
            // no matter what I do the scroll bar handle occupies the enire bar and doesn't move
    
            // The Qt.ScrollBarAsNeeded didn't work... so I did this
            verticalScrollBarPolicy: scrollBarVisible ? Qt.ScrollBarAlwaysOn : Qt.ScrollBarAlwaysOff
    
            ListView
            {
                id: myListView
                model: wifiComboListModel
    
                focus: true
                clip: true
                interactive: false
    
                width: parent.width
    
                // I am trying to tell my view to take the minimum space it needs that is below
                // a certain height. Ignore the "myListView." prefixes here, I know they are not needed but
                // make it easier to move this outside if needed
                height: (myListView.contentHeight > 0 ?
                             (myListView.contentHeight < parentMaxHeight ?
                                  myListView.contentHeight : parentMaxHeight) : 0)
    
                // I made this as simple as possible, without affecting "quality"
                delegate: Text
                {
                    text: _comboBoxText
                    height: 70
                    width: parent.width - 20
                }
            }
        }
    
        ListModel
        {
            id: wifiComboListModel
        }
    
        // I want to populate my model from outside, not be static. Not sure if this affects the bars
        function populateComboBoxListModel()
        {
            wifiComboListModel.clear();
            for (var itemIndex = 0; itemIndex < listItems.length; itemIndex++)
            {
                wifiComboListModel.append
                    ({
                        _id: itemIndex,
                        _comboBoxText: listItems[itemIndex]
                    });
            }
        }
    
        Component.onCompleted:
        {
            populateComboBoxListModel();
        }
    
        property var listItems: [
                "This",
                "annoying",
                "list",
                "view",
                "does",
                "not behave the way",
                "I expect.",
                "I",
                "tried many",
                "things,",
                "now I am",
                "begging for your",
                "help",
                "."
        ]
    }
    

    【讨论】:

    • 很抱歉,这仍然对我不起作用。该更改仅使矩形具有固定的最大大小,我将其与列表视图相关联的原因是它会根据内容调整大小。一旦我的同事帮助解决了问题,我也确实看到了绑定循环错误,我将不得不以不同的方式计算高度 - 所以你指出的问题是有效的。我将在下面解释是什么解决了这个问题。
    • 修复 - 包含在您的代码中,但您没有指出 - 将 ListView 物理嵌套在 ScrollView 中。我在下面的答案中对此进行了解释,也许它会对其他人有所帮助,但我赞成并将您的答案标记为正确。
    【解决方案2】:

    我的 ScrollView 不正常的原因是父母身份 :)

    问题:即使我在 ListView 中设置了父级,似乎也没有:

    ListView
    {
        parent: myScrollView
    

    我必须做的实际上是将 ListView 嵌套在 ScrollView 中。

    ScrollView
    {
        id: myScrollView
        parent: myMenuRect
        anchors.fill: parent
    
        ListView
        {
            id: myListView
            model: wifiComboListModel
    

    我认为“父”属性可能不适用于所有控件,并且将来会记住这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多