Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Custom ScrollBar to add top & bottom buttons (Windows Style)
QtWS25 Last Chance

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

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
5 Posts 2 Posters 3.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    DiegoDonate
    wrote on 1 Mar 2018, 08:48 last edited by
    #1

    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
                }
            }
        }
    }
    
    1 Reply Last reply
    0
    • J Offline
      J Offline
      jpnurmi
      wrote on 1 Mar 2018, 09:44 last edited by
      #2

      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
              }
          }
      }
      
      D 1 Reply Last reply 1 Mar 2018, 10:49
      0
      • J jpnurmi
        1 Mar 2018, 09:44

        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
                }
            }
        }
        
        D Offline
        D Offline
        DiegoDonate
        wrote on 1 Mar 2018, 10:49 last edited by DiegoDonate 3 Jan 2018, 11:20
        #3

        @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?

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jpnurmi
          wrote on 1 Mar 2018, 11:23 last edited by
          #4

          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/

          D 1 Reply Last reply 1 Mar 2018, 12:04
          1
          • J jpnurmi
            1 Mar 2018, 11:23

            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/

            D Offline
            D Offline
            DiegoDonate
            wrote on 1 Mar 2018, 12:04 last edited by
            #5

            @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?

            1 Reply Last reply
            0

            1/5

            1 Mar 2018, 08:48

            • Login

            • Login or register to search.
            1 out of 5
            • First post
              1/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved