Move QML ListView via buttons



  • Hello,

    I would like to be able to move a list view via button, with the following behaviors:

    1. Move repeatedly when I click several time on button

    2. Move continuously on press and hold

    3. Display the scrollbar when moving via buttons


    I tried several methods:

    • Use positionViewAtIndex() method

    Instantaneous change without smooth moving.

    • Moving the currentIndex

    Not working properly if current index is not a visible item.
    Delay before moving when currentIndex change the first time (around 1s) .

    • Use flick() method

    Works for moving
    Only method which allow to display the scroll bar when moving
    Cannot click repeatedly on the button, the previous flick has to be finished.

    I still don't know how to achieve smooth moving when clicking repeatedly, neither how to move continuously on press and hold.


    My current demo with flick method:

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    Rectangle {
        property color accentColor: "#ff00b374"
    
        id: demo
        width: 800
        height: 600
    
        color: "#ff303030"
    
        Rectangle {
            width: parent.width/2-32
            height: parent.height-32
            x: 16
            y: 16
    
            color: accentColor
            clip: true
            ListView {
                id: listView
                width: parent.width
                height: parent.height
    
                // When scroll end align to the nearest item
                snapMode: ListView.SnapToItem
                // Clip painting to his own bounding rectangle to avoid display
                // data outside specified size during flick
                clip: true
                model: 100
    
                // Increase Flick speed
                maximumFlickVelocity: 10000
                cacheBuffer:1000
    
                ScrollBar.vertical: ScrollBar {
                    id: verticalScrollBar
                    active: true
                    orientation: Qt.Vertical
                    opacity: verticalScrollBar.pressed?1:(listView.moving?1:0)
                    Behavior on opacity {NumberAnimation {duration: 500}}
    
                    contentItem: Rectangle {
                        implicitWidth: 4
                        radius:2
                        implicitHeight: parent.height
                        color: accentColor
                    }
                }
    
                delegate: Rectangle {
                    id: lineRectangle
                    height: 32
                    width: listView.width
    
                    // Change color based on index number for better readability
                    color: (index & 1)? "#ffefefef" : "#ffffffff"
    
                    Text {
                        id: textField
                        height: parent.height
                        width: parent.width
                        color: listView.currentIndex === index? accentColor:"#ff000000"
                        font.pixelSize: 16
                        horizontalAlignment : Text.AlignHCenter
                        text: "Element " + (index+1)
                    }
                }
            }
        }
    
        // Up Button to move list up
        Rectangle {
            id: upButton
    
            height: 256
            width: height//parent.width
            radius: height/2
    
            x: parent.width*3/4-width/2
            y: parent.height*1/4-height/2
    
            color: "#ffffffff"
    
            Text {
                text: "Up"
                anchors.centerIn: parent
                color: listUp.pressed? demo.accentColor: "#ff000000"
                font.pixelSize: 64
            }
    
            MouseArea {
                anchors.fill: parent
                id: listUp
                onPressed: {
                    listView.flick(0, 1000)
                    /*var targetIndex = listView.currentIndex-20;
                    if (targetIndex < 0)
                        listView.currentIndex= 0;
                    else
                        listView.currentIndex= targetIndex*/
                }
            }
        }
    
        // Down Button to move list down
        Rectangle {
            id: downButton
            height: upButton.height
            width: upButton.width
            radius: upButton.radius
            color: upButton.color
    
            x: parent.width*3/4-width/2
            y: parent.height*3/4-height/2
    
            Text {
                text: "Down"
                anchors.centerIn: parent
                color: listDown.pressed? demo.accentColor: "#ff000000"
                font.pixelSize: 64
            }
    
            MouseArea {
                anchors.fill: parent
                id: listDown
                onClicked: {
                    listView.flick(0, -1000);
                    /*var targetIndex = listView.currentIndex+20;
                    if (targetIndex >= listView.count)
                        listView.currentIndex= listView.count-1;
                    else
                        listView.currentIndex= targetIndex*/
                }
            }
        }
    }
    
    
    


  • HI,

    Solution to your first point "Move repeatedly when I click several time on button". Please find below

    You have to do few things

    1. please call accentColor everywhere using the id "demo", as what you called in other places.
    2. In ListView, onCompleted slot, set the listView's current index to 0. (listView.currentIndex = 0)
    3. In onMousePressed for UP button, use the following lines
      if (listView.currentIndex < listView.count-1)
      {
      listView.currentIndex += 1
      }
    4. In onMousePressed for Down button, use the following lines
      if (listView.currentIndex > 0)
      {
      listView.currentIndex -= 1
      }


  • Hi,

    You can also find an example of programmatically scrolling a ListView in this github sample.

    It uses the AppListView component from the V-Play SDK, but the approach should work as well with a plain Qt ListView.

    Cheers,
    Lorenz



  • Hello @AbuFahima,

    I already tried this method (see my first post), it is also in comment in my example and the currentIndex is highlighted.

    But I found theses issues with this method:

    • Moving the currentIndex

    Not working properly if current index is not a visible item.
    Delay before moving when currentIndex change the first time (around 1s) .



  • Hello @Lorenz,

    The method you show me use positionViewAtIndex() and I also tried this and I have this issue:

    • Use positionViewAtIndex() method

    Instantaneous position change without smooth moving.



  • Something like this?

    import QtQuick 2.7
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.0
    
    Window {
        id: demo
        width: 800
        height: 600
        visible: true
        color: "#ff303030"
    
        property color accentColor: "#ff00b374"
    
        Rectangle {
            width: parent.width/2-32
            height: parent.height-32
            x: 16
            y: 16
    
            color: accentColor
            clip: true
            ListView {
                id: listView
                width: parent.width
                height: parent.height
    
                // When scroll end align to the nearest item
                snapMode: ListView.SnapToItem
                // Clip painting to his own bounding rectangle to avoid display
                // data outside specified size during flick
                clip: true
                model: 100
    
                // Increase Flick speed
                maximumFlickVelocity: 10000
                cacheBuffer:1000
    
                ScrollBar.vertical: ScrollBar {
                    id: verticalScrollBar
                    active: pressed || listView.moving || listUp.pressed || listDown.pressed
                    orientation: Qt.Vertical
                    opacity: active ? 1:0
                    Behavior on opacity {NumberAnimation {duration: 500}}
    
                    contentItem: Rectangle {
                        implicitWidth: 4
                        radius:2
                        implicitHeight: parent.height
                        color: accentColor
                    }
                }
    
                delegate: Rectangle {
                    id: lineRectangle
                    height: 32
                    width: listView.width
    
                    // Change color based on index number for better readability
                    color: (index & 1)? "#ffefefef" : "#ffffffff"
    
                    Text {
                        id: textField
                        height: parent.height
                        width: parent.width
                        color: listView.currentIndex === index? accentColor:"#ff000000"
                        font.pixelSize: 16
                        horizontalAlignment : Text.AlignHCenter
                        text: "Element " + (index+1)
                    }
                }
            }
        }
    
        // Up Button to move list up
        Rectangle {
            id: upButton
    
            height: 256
            width: height//parent.width
            radius: height/2
    
            x: parent.width*3/4-width/2
            y: parent.height*1/4-height/2
    
            color: "#ffffffff"
    
            Text {
                text: "Up"
                anchors.centerIn: parent
                color: listUp.pressed? demo.accentColor: "#ff000000"
                font.pixelSize: 64
            }
    
            MouseArea {
                anchors.fill: parent
                id: listUp
    
                SmoothedAnimation {
                    target: listView
                    property: "contentY"
                    running: listUp.pressed
                    velocity: 1000
                    to: 0
                }
                onReleased: {
                    if (!listView.atYBeginning)
                        listView.flick(0, 1000)
                }
            }
        }
    
        // Down Button to move list down
        Rectangle {
            id: downButton
            height: upButton.height
            width: upButton.width
            radius: upButton.radius
            color: upButton.color
    
            x: parent.width*3/4-width/2
            y: parent.height*3/4-height/2
    
            Text {
                text: "Down"
                anchors.centerIn: parent
                color: listDown.pressed? demo.accentColor: "#ff000000"
                font.pixelSize: 64
            }
    
            MouseArea {
                anchors.fill: parent
                id: listDown
    
                SmoothedAnimation {
                    target: listView
                    property: "contentY"
                    running: listDown.pressed
                    to: listView.contentHeight - listView.height
                    velocity: 1000
                }
                onReleased: {
                    if (!listView.atYEnd)
                        listView.flick(0, -1000)
                }
            }
        }
    }
    


  • Thanks @jpnurmi,

    This is exactly what i was looking for, all my issues are solved.


Log in to reply
 

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