Custom ScrollBar to add top & bottom buttons (Windows Style)



  • I have a QT application and need to custom my ListView ScrollBar, to have a Windows Look&Fell scroll, including top and bottom buttons (to scroll up or down when clicked)

    As far as I know, all I can customize from ScrollBar is the contentItem and the background. There is no default way to add these top & bottom buttons. To add it manually

    To add buttons at top & bottom I have added margins in the contentItem, so I have space for my buttons. But with that margin, the height of the contentItem is smaller and with a lot of elements in my ListView the handle is NOT visible...

    Is it possible to have a minimum height for the contentItem? Is there any other way to have this 2 buttons?

    Thanks in advance

    Code:

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    Item {
        anchors.fill: parent
    
        MouseArea {
          anchors.fill: id_list
          onWheel: id_list.flick(0, wheel.angleDelta.y * 5)
        }
    
        ListModel {
             id: listModel
             Component.onCompleted: {
                 for (var i = 0; i < 1000; i++)
                     append({ role_text: "Item " + i});
             }
         }
    
        ListView {
            id: id_list
            anchors.fill: parent
    
            interactive: false
            boundsBehavior: Flickable.StopAtBounds
            focus: true
    
            Keys.onPressed: {
              if (event.key === Qt.Key_Up) id_list.flick(0, 500)
              else if (event.key === Qt.Key_Down) id_list.flick(0, -500)
            }
    
            keyNavigationEnabled: true
    
            model: listModel
            ScrollBar.vertical: ScrollBar {
                id: id_scroll
                interactive: true;
                policy: ScrollBar.AlwaysOn
                anchors { top: parent.top; topMargin: 0; bottom: parent.bottom; bottomMargin: 0; right: parent.right/*; rightMargin: -2*/}
    
                contentItem: Item {
                    implicitWidth: 11
                    implicitHeight: 100
    
                    Rectangle {
                        anchors { top: parent.top; topMargin: 13; bottom: parent.bottom; bottomMargin: 13; left: parent.left; leftMargin: -2; right: parent.right; rightMargin: -2}
                        color: "green"
                    }
                }
    
                background: Item {
                    implicitWidth: 11
                    implicitHeight: id_scroll.height
    
                    Rectangle {
                        anchors { top: parent.top; bottom: parent.bottom; bottomMargin: 0; left: parent.left; right: parent.right}
                        color: "#ededed"
                    }
    
                    Rectangle {
                        anchors { top: parent.top; right: parent.right }
                        height: 15; width: height
                        color: "red"
                        MouseArea {
                            anchors.fill: parent
                            onClicked: id_list.flick(0, 500)
                        }
                    }
                    Rectangle {
                        anchors { bottom: parent.bottom; right: parent.right }
                        height: 15; width: height
                        color: "red"
                        MouseArea {
                            anchors.fill: parent
                            onClicked: id_list.flick(0, -500)
                        }
                    }
                }
            }
    
            delegate: Rectangle {
                height: 40
                width: id_list.width
                color: "white"
                border { color: "black"; width: 1 }
                TextEdit {
                    anchors.centerIn: parent
                    id: id_text
                    text: role_text;
                    selectByMouse: true;
                    readOnly: true;
                    persistentSelection: true
                }
            }
        }
    }
    


  • You can use Control::topPadding and bottomPadding to reserve space:

    import QtQuick 2.9
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        id: window
        width: 400
        height: 400
        visible: true
    
        ListView {
            id: listView
    
            model: 100
            anchors.fill: parent
    
            ScrollBar.vertical: ScrollBar {
                id: vbar
    
                topPadding: 16 + 2
                bottomPadding: 16 + 2
    
                Rectangle {
                    width: parent.width
                    height: 16
                    color: upButton.pressed ? "blue" : "red"
                    opacity: vbar.contentItem.opacity
    
                    MouseArea {
                        id: upButton
                        anchors.fill: parent
    
                        SmoothedAnimation {
                            target: listView
                            property: "contentY"
                            running: upButton.pressed
                            velocity: 1000
                            to: 0
                        }
    
                        onReleased: {
                            if (!listView.atYBeginning)
                                listView.flick(0, 1000)
                        }
                    }
                }
    
                Rectangle {
                    y: parent.height - height
                    width: parent.width
                    height: 16
                    color: downButton.pressed ? "blue" : "red"
                    opacity: vbar.contentItem.opacity
    
                    MouseArea {
                        id: downButton
                        anchors.fill: parent
    
                        SmoothedAnimation {
                            target: listView
                            property: "contentY"
                            running: downButton.pressed
                            to: listView.contentHeight - listView.height
                            velocity: 1000
                        }
    
                        onReleased: {
                            if (!listView.atYEnd)
                                listView.flick(0, -1000)
                        }
                    }
                }
            }
    
            delegate: ItemDelegate {
                text: modelData
                width: parent.width
            }
        }
    }


  • @jpnurmi Thanks for your help!!

    Now I have to face the 2nd problem, the handle height. If you add 1000 elements to the list, the scrollbar contentItem is not visible, due to the dinamic size... How can I set a minimum height for the scroll handle?



  • ScrollBar::minimumSize has been added in Qt Quick Controls 2.4 (Qt 5.11). The first beta was just released if you want to try it out: http://blog.qt.io/blog/2018/03/01/qt-5-11-beta-released/



  • @jpnurmi Thanks. I am working with Qt 5.9.4 libraries (compiled from source) and can not update right now to 5.11. Is there anything I can do with this Qt version?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.