Flickable / ScrollView in QML with always-visible scrollbars that don't overlap in the bottom right corner

Viewed 363

I'm trying to implement a widget similar to the default ScrollView widget, except the scrollbars are always visible and are much thicker + easier to see. There doesn't seem to be an easy way to actually theme or adjust the styling of the scrollbars on ScrollView to get what I want, so I've ended up trying to hack Flickable to do this.

However, overriding the scrollbars in Flickable like this has one downside: It turns out that it either makes the scrollbars overlap in the bottom right corner, OR the vertical one stretches all the way down, and the horizontal one fits in the remaining space. What should happen instead is that there should be a tiny square left over in the corner where neither scrollbar should go.

Using the anchors.bottom / anchors.right lines, I can get that corner to behave as expected. But at the expense of the top/left sides of the scrollbars now being out of view.

I can "solve" this start-of-scrollbars-out-of-view issue by assigning the top/left anchors (i.e. commented lines) to the corresponding flickable boundaries. However, while it looks ok, it results in a stream of QML ScrollBar: Possible anchor loop detected on vertical anchor. warnings flooding the console. Is there any way to avoid this anchor loop error, or should I just look to ignore/filter those warnings?


The code ("ScrollPane.qml"):

/// ScrollPane - Custom ScrollView-like widget based on Flickable,
/// with additional functionality for getting the theming we want.
import QtQuick 2.3
import QtQuick.Controls 2.3

// The region that displays the contents
Flickable {
    id: flickable
    clip: true
    
    boundsBehavior: Flickable.StopAtBounds
    //boundsMovement: Flickable.StopAtBounds
    
    // Increase scrolling speed, as Flickable is too sluggish
    // Note: Windows default is 2500
    
    //maximumFlickVelocity : 10000  // XXX: overshoots
    maximumFlickVelocity : 7000
    
    // Component.onCompleted: {
    //  console.log("scroll view rate = %1".arg(maximumFlickVelocity))
    // }
    
    // Scrollbars ===========================
    
    // Scrollbar Parameters -----------------
    
    // Width/Thickness of Gutter (px)
    property int gutterSize : 18
    
    // Width/Thickness of Scroll Thumb (px)
    property int thumbSize : gutterSize - 3
    
    
    // Gutter Color
    property color gutterColor: "#FFFFFF"
    property color gutterBorderColor: Qt.rgba(0, 0, 0, 0.9)
    
    // Scroll Thumb Colors
    property color thumbColor: "#BBBBBB"
    property color thumbPressedColor: "#777777"
    property color thumbBorderColor: "#CCCCCC"
    
    // Vertical Scrollbar: Always On --------
    ScrollBar.vertical: ScrollBar {
        id: verticalScrollbar
        
        policy: ScrollBar.AlwaysOn
        
        /// NOTE: This is needed to keep the bottom-right corner empty. But, is buggy due to the Anchor Loop warning
        //anchors.top: flickable.top  // FIXME: Enable to show rounded top; Disabled due to Anchor Loop warning
        anchors.bottom: horizontalScrollbar.top
        
        // Gutter/Trough
        background: Rectangle {
            implicitWidth: flickable.gutterSize
            border {
                color: flickable.gutterBorderColor
                width: 1.5
            }
            color: flickable.gutterColor
            opacity: 0.2
        }
        
        // Scroll Thumb
        contentItem: Rectangle {
            implicitWidth: flickable.thumbSize
            radius: width / 2
            border {
                color: flickable.thumbBorderColor
                width: 1
            }
            color: parent.pressed ? flickable.thumbPressedColor
                                  : flickable.thumbColor
            opacity: 0.9
        }
    }
    
    // Horizontal Scrollbar: As Needed --------
    ScrollBar.horizontal: ScrollBar {
        id: horizontalScrollbar
        
        policy: ScrollBar.AsNeeded
        

        /// NOTE: This is needed to keep the bottom-right corner empty. But, is buggy due to the Anchor Loop warning
        //anchors.left: flickable.left // FIXME: Enable to show rounded LHS; Disabled due to Anchor Loop warning
        anchors.right: verticalScrollbar.left
        
        // Gutter/Trough
        background: Rectangle {
            implicitHeight: flickable.gutterSize
            border {
                color: flickable.gutterBorderColor
                width: 1.5
            }
            color: flickable.gutterColor
            opacity: 0.2
        }
        
        // Scroll Thumb
        contentItem: Rectangle {
            implicitHeight: flickable.thumbSize
            radius: height / 2
            border {
                color: flickable.thumbBorderColor
                width: 1
            }
            color: parent.pressed ? flickable.thumbPressedColor
                                  : flickable.thumbColor
            opacity: 0.9
        }
    }
}

1 Answers

Well, you can disable the automatic resizing of the scrollbars when choosing another parent:

    ScrollBar.vertical: ScrollBar {
        id: verticalScrollbar

        policy: ScrollBar.AlwaysOn

        parent: flickable.parent

        anchors.top: flickable.top
        anchors.right: flickable.right
        anchors.bottom: flickable.bottom
        anchors.bottomMargin: 20
    }

    ScrollBar.horizontal: ScrollBar {
        id: horizontalScrollbar

        policy: ScrollBar.AsNeeded

        parent: flickable.parent
        anchors.left: flickable.left
        anchors.right: flickable.right
        anchors.bottom: flickable.bottom
        anchors.rightMargin: 20
   } 

Does this meet your needs?

Related