QML自定义实现ScrollBar

本文档详细介绍了如何在QtQuick中创建一个自定义的竖向滚动条组件,包括与QtListView、QtFlickable等组件的配合使用。滚动条具备自动隐藏功能,可切换宽窄状态,并提供了详细的鼠标事件处理和状态转换逻辑。同时,展示了滚动条的轨道和滑块组件的样式定义。
摘要由CSDN通过智能技术生成
import QtQuick 2.6

/* 滚动条-竖向
滚动条可配合 Qt ListView ,Qt Flickable ,等等使用。
 TScrllbarV{
    target:listView;
 }

*/
Item {
    id:toou2d_scrollbarv;
    width: 22;

    property Flickable target: parent;

    //0 - 1
    property double yPosition: 0;

    //可变小  ,true 启动状态为 narrowed false 启动状态为 full
    property bool narrowed: false;

    property bool autoHide: false;

    //Too small a height affects drag accuracy
    property int thumbMinHieght: 30;

    property int stateDuration: 1000;

    property Component thumbComponent;

    property Component trackComponent;

    state: narrowed ? "narrowed" : "full";

    Loader{
        id:track;
        anchors.right: parent.right;
        sourceComponent: trackComponent;
        height:  parent.height;
        visible: true;
    }

    Loader{
        id:thumb
        anchors.horizontalCenter: track.horizontalCenter;
        sourceComponent: thumbComponent;
        visible: true;
        height:  thumbMinHieght;
    }

    MouseArea{
        id:mouseArea
        property bool ishold: false;

        property bool isdrag: false;

        property double offset: 0;

        //anchors.fill: parent;
        width: parent.width;

        height: parent.height;

        hoverEnabled: true;

        onWheel: {
        }

        onPressed: {
            ishold = true;
            if(mouseY > thumb.y && mouseY < thumb.height + thumb.y){
                offset  = mouseY - thumb.y;
                isdrag = true;
            }else{
                mprivate.setValue(mouseY - thumb.height / 2)
            }
        }

        onReleased: {
            ishold = false;
            isdrag = false;
            if(!containsMouse){
                stateTimer.rStart();
            }
        }

        onEntered: {
            toou2d_scrollbarv.state = "full";
            stateTimer.stop();
        }

        onExited: {
            if(!ishold)stateTimer.rStart();
        }

        onMouseYChanged: {
            if(ishold && isdrag){
                mprivate.setValue(mouseY - offset)
            }
        }

        Component.onCompleted: {
            mprivate.checkVisible();
        }

        onIsholdChanged: target.interactive = !ishold;
    }

    onYPositionChanged: {
        if(mouseArea.ishold){//drag interior setting
            target.contentY = (target.contentHeight - target.height) * yPosition;
        }
    }

    Connections{
        target: toou2d_scrollbarv.target;
        onContentYChanged:{
            if(!mouseArea.ishold){
                var t = toou2d_scrollbarv.target;
                var p = t.contentY / (t.contentHeight - t.height);
                mprivate.setValue(p * (height - thumb.height))
            }

            mprivate.restoreVisibleState();
        }

        onContentHeightChanged:{
            var t  = toou2d_scrollbarv.target;
            var nh = t.height / t.contentHeight * toou2d_scrollbarv.height;
            if(nh > thumbMinHieght){
                thumb.height = nh;
            }
            mprivate.checkVisible();
        }

        onHeightChanged:mprivate.checkVisible();
    }

    QtObject{
        id:mprivate;

        function setValue(v){
            if(v < 0){
                thumb.y = 0;
            }else if(v + thumb.height > height){
                thumb.y = height - thumb.height;
            }else{
                thumb.y = v;
            }

            yPosition = thumb.y / (height -  thumb.height);
        }

        function checkVisible(){
            var t = toou2d_scrollbarv.target;
            if(t){
                //计算是否显示滚动条
                toou2d_scrollbarv.visible = t.contentHeight > t.height;
                toou2d_scrollbarv.enabled = toou2d_scrollbarv.visible;
            }
        }

        function restoreVisibleState(){
            if(!mouseArea.containsMouse && !mouseArea.ishold && !stateTimer.running){
                if(toou2d_scrollbarv.narrowed){
                    toou2d_scrollbarv.state = "narrowed";
                }else{
                    toou2d_scrollbarv.state = "full";
                }
                stateTimer.rStart();
            }
        }
    }

    //滑槽
    trackComponent: Rectangle{
        id:mt
        state: toou2d_scrollbarv.state;
        color: "#E5E5E5"
        opacity: 0.1
        states: [
            State {
                name: "full"
                PropertyChanges {
                    target: mt
                    color:"#5d5d5d"
                    width: 15;
                }
            },
            State {
                name: "narrowed"
                PropertyChanges {
                    target: mt
                    width:15;
                    visible:false;
                }
            },
            State {
                name: "hide"
                PropertyChanges {
                    target: mt
                    visible:false;
                }
            }
        ]
    }

    //滑块
    thumbComponent: Rectangle{
        id:mth
        state: toou2d_scrollbarv.state;
        radius: width / 2;
        color: "#B2B2B2"
        states: [
            State {
                name: "full"
                PropertyChanges {
                    target: mth
                    width:8;
                }
            },
            State {
                name: "narrowed"
                PropertyChanges {
                    target: mth
                    width:8;
                }
            },
            State {
                name: "hide"
                PropertyChanges {
                    target: mth
                    visible:false;
                }
            }
        ]
    }

    Timer{
        id:stateTimer;
        property bool isrun:  narrowed || autoHide
        interval: stateDuration; running: isrun ; repeat : true;
        onTriggered:{
            if(toou2d_scrollbarv.state === "full"){
                if(toou2d_scrollbarv.narrowed){
                    toou2d_scrollbarv.state = "narrowed";
                }
                else if(toou2d_scrollbarv.autoHide){
                    toou2d_scrollbarv.state = "hide";
                }
            }
            else if(toou2d_scrollbarv.state === "narrowed"){
                if(toou2d_scrollbarv.autoHide){
                    toou2d_scrollbarv.state = "hide";
                }
            }

            if(toou2d_scrollbarv.state === "hide"){
                stop();
            }
        }

        function rStart(){
            if(isrun)restart();
        }
    }

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值