Shubham Gupta
Shubham Gupta

Reputation: 31

How to make Rectangle behaves like a scrollbar in qml

I am trying to make a scroll bar without using ScrollBar Component in QML. So i have made this component and attach to the ListView. But it doesn't flick the listview items.

I want, this rectangle scrolls the content of ListView or GridView on scrolling.

What I did?

Ist I create a rectangle then make another rectangle as a child of ist one. And applied the dragging technique on Y axis and set the coordinates for y axis.

My Code is given below:

import QtQuick 2.0
Rectangle{
    property bool is_parentDrag: false
    property bool is_childDrag: false
    id:parent_screen
    anchors.fill:parent
    color:"#ebeaee"
    Rectangle{
        id:foot
        width:parent.width*0.9
        height:parent.height*0.133
        color:"#ffffff"
        border.width:1
        anchors.bottom:parent.bottom
        anchors.bottomMargin:lv.height*0.005
        anchors.horizontalCenter: parent.horizontalCenter
        Rectangle{
            width:parent.width*0.125
            height:parent.height*0.5
            radius:20
            anchors.verticalCenter: parent.verticalCenter
            anchors.left: parent.left
            anchors.leftMargin: parent.height*0.2
            color:"transparent"

            Image{
                source: "left_direction_icon.png"
                anchors.centerIn:  parent
                sourceSize.width: parent.width*0.4
                sourceSize.height: parent.width*0.4

            }
            MouseArea{
                anchors.fill:parent
                onClicked: {
                    stack.pop()
                }
            }
        }
    }
    Flickable{
        id:flick_1
        width:parent.width*0.9
        height:parent.height*0.7
        anchors.centerIn: parent
        flickableDirection:Flickable.HorizontalFlick
        boundsBehavior: Flickable.StopAtBounds
        ListView{
            id:lv
            clip:true
            boundsBehavior: Flickable.StopAtBounds
            height:parent.height
            width:parent.width*0.9
            anchors.left:parent.left
            anchors.leftMargin: parent.width*0.11
            model:Data{}
            delegate: Rectangle{
                id:delg
                width:lv.width*0.5
                height:lv.height*0.170
                Text{
                    text:txt
                    anchors.centerIn: parent
                    font.pixelSize: 22
                }
                Rectangle{
                    id:right
                    width:1
                    height:parent.height
                    color:"black"
                    anchors.right:parent.right
                }
                Rectangle{
                    id:bottom
                    width:parent.width
                    height:1
                    color:"black"
                    anchors.bottom:parent.bottom
                }
                Rectangle{
                    id:left
                    width:1
                    height:parent.height
                    color:"black"
                    anchors.left:parent.left
                }
            }
            Rectangle{
                id:scrollbar
                width:flick_1.width*0.02
                height:flick_1.height
                visible: lv.contentHeight>lv.height
                radius:width/2
                color:"lightgrey"
                anchors.right: lv.right
                anchors.rightMargin: lv.width*0.1
                Rectangle {
                    id:scroll
                    Drag.active:is_parentDrag?parent_drag_area.drag.active:is_childDrag?drag_area.drag.active:false
                    Drag.source: scroll
                    implicitWidth: parent.width
                    implicitHeight: parent.height*0.7
                    radius:width/2
                    opacity:0.85
                    color: "grey"

                    MouseArea{
                        id:drag_area
                        anchors.fill:parent
                        drag.target: scroll
                        drag.axis: Drag.YAxis
                        drag.minimumY: 0
                        drag.maximumY: scrollbar.height-scroll.height
                        onPressed:{
                            if(is_childDrag)
                                is_childDrag=false
                            else
                                is_childDrag=true
                        }

                    }
                }
                MouseArea{
                    id:parent_drag_area
                    anchors.fill:parent
                    drag.target: scroll
                    drag.axis: Drag.YAxis
                    drag.minimumY: 0
                    drag.maximumY: scrollbar.height-scroll.height
                    onPressed:{

                        if(is_parentDrag)
                            is_parentDrag=false
                        else
                            is_parentDrag=true
                    }

                }


            }
//            Rectangle {
//                id: scrollbar
//                //height:parent.height*0.04
//                width:parent.width
//                radius:width/2
//                anchors.bottom: parent.bottom
//                y: flick_1.visibleArea.yPosition * flick_1.height
//                height: flick_1.visibleArea.heightRatio * flick_1.height*0.04
//                color: "lightgrey"
//                anchors.bottomMargin: parent.height*0.1
//                Rectangle {
//                    id:scroll
//                     y: flick_1.visibleArea.yPosition * flick_1.height
//                    implicitWidth: parent.width*0.7
//                    implicitHeight: parent.height
//                    radius:width/2
//                    opacity:0.85
//                    color: "grey"
//                }
//            }
        }




    }
}

Upvotes: 0

Views: 1186

Answers (2)

Benjamin T
Benjamin T

Reputation: 8321

A solution is to leverage Qt Quick Templates 2. This Qt module is the base of Qt own controls Qt Quick Controls 2 and contains multiple base UI components that can be fully customized.

In your case, you should look at ScrollBar and how to customize it.

Your code could end up being something like this:

Flickable {
    id: flickable
    clip: true
    // ...
    ScrollBar.vertical: ScrollBar {
        id: control
        size: 0.3
        position: 0.2
        active: true
        orientation: Qt.Vertical

        contentItem: Rectangle {
            implicitWidth: 6
            implicitHeight: 100
            radius: width / 2
            color: control.pressed ? "#81e889" : "#c2f4c6"
        }
    }
}

Upvotes: 0

sk2212
sk2212

Reputation: 1722

You can try this (copied from QML Material Project).

Create a new QML-File called ScrollbarCustom.qml:

Item {
    id: root

    property Flickable flickableItem
    property int orientation: Qt.Vertical
    property int thickness: 5
    property bool moving: flickableItem.moving

    property alias currentY: scrollBar.y

    width: thickness
    height: thickness
    clip: true
    smooth: true
    visible: orientation === Qt.Vertical ? flickableItem.contentHeight > flickableItem.height
                                         : flickableItem.contentWidth > flickableItem.width

    anchors {
        top: orientation === Qt.Vertical ? flickableItem.top : undefined
        bottom: flickableItem.bottom
        left: orientation === Qt.Horizontal ? flickableItem.left : undefined
        right: flickableItem.right
        margins: 2
    }

    signal stopAnimation

    onStopAnimation: {
        hideAnimation.stop();
        showAnimation.start();
    }

    signal startAnimation

    onStartAnimation: {
        hideAnimation.start();
        showAnimation.stop();
    }

    Component.onCompleted: hideAnimation.start()

    onMovingChanged: {
        if (moving) {
            hideAnimation.stop()
            showAnimation.start()
        } else {
            hideAnimation.start()
            showAnimation.stop()
        }
    }

    NumberAnimation {
        id: showAnimation
        target: scrollBar;
        property: "opacity";
        to: 0.3;
        duration: 200;
        easing.type: Easing.InOutQuad
    }

    SequentialAnimation {
        id: hideAnimation

        NumberAnimation { duration: 500 }
        NumberAnimation {
            target: scrollBar;
            property: "opacity";
            to: 0;
            duration: 500;
            easing.type: Easing.InOutQuad
        }
    }

    onOrientationChanged: {
        if (orientation == Qt.Vertical) {
            width = thickness
        } else {
            height = thickness
        }
    }

    Rectangle {
        id: scrollBar
        property int length: orientation == Qt.Vertical ? root.height
                                                        : root.width;
        property int targetLength: orientation == Qt.Vertical ? flickableItem.height
                                                              : flickableItem.width;
        property int contentStart: orientation == Qt.Vertical ? flickableItem.contentY
                                                              : flickableItem.contentX;
        property int contentLength: orientation == Qt.Vertical ? flickableItem.contentHeight
                                                               : flickableItem.contentWidth;
        property int start: Math.max(0, length * contentStart/contentLength);
        property int end: Math.min(length,
                                   length * (contentStart + targetLength)/contentLength)

        color: Theme.accentColor //"black"//theme.foreground
        opacity: 0.2
        radius: thickness/2
        width: Math.max(orientation == Qt.Horizontal ? end - start : 0, thickness)
        height: Math.max(orientation == Qt.Vertical ? end - start : 0, thickness)
        x: orientation == Qt.Horizontal ? start : 0
        y: orientation == Qt.Vertical ? start : 0
    }
}

And use it like this:

       Flickable {
            id: flickable

            clip: true

            anchors {
                top: parent.top
                left: parent.left
                right: parent.right
                bottom: parent.bottom
            }
      }

      ScrollbarCustom {
          flickableItem: flickable
      }

Upvotes: 0

Related Questions