Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

horizontal scrollbar get lost when switching from QtQuick.Controls 1.1 to 2.14?



  • UPDATE: is not the vertical scrollbar - its the horizontal scrollbar that is going away when switching to 2.14 - mixed up vertical/horizontal

    im currently working on a gantt chart that should help visualize task activities

    gantt.png

    schema is(should be) like this:

    gantt.schema.png

    first time in months that i touched QML again so i started with QtQuick 1.1 controls
    but now i want to switch to 2.14 and then my horizontal scrollbar in the gantt chart stops working

    small videos showing the effect:
    with qtquick 1.1: https://streamable.com/9oxixv
    with qtquick 2.14: https://streamable.com/jskeh3

    the complete files: main.qml + TaskSimulation.qml: https://filehorst.de/d/dhBuweyi

    my ListView contentWidth automatic growths with the time axis + a litte distance

    my main.qml

    import QtQuick 2.14
    import QtQuick.Shapes 1.14
    
    //import QtQuick.Controls 1.1
    import QtQuick.Controls 2.14 // no horizontal scrollbar when using 2.14
    
    ApplicationWindow {
        id: myApp
    
        visible: true
        width: 800
        height: 800
        title: qsTr("QML Gantt Test")
    
        // visual styles
        readonly property int barHeight: 40
        readonly property int innerBarHeight: barHeight - 2
        readonly property int taskInfoWidth: 152
        readonly property color backgroundColor: "#ccc"
    
        // states
        readonly property int futureDistance: 100 // space left to the time axis (the unknown future)
        property int fullGanttSpace: sim.ticks + futureDistance
        property int posInTime: sim.ticks
        property ListModel taskModel: sim.taskModel // [{taskName, ranges[{start, duration},...]},...]
    
        // Simulates fix amount of tasks + ongoing activity
        TaskSimulation
        {
            id:sim
            intervalInMsec: 50
            taskCount: 10
        }
    
        Component.onCompleted: {
            sim.start()
        }
    
        Rectangle{
            id: ganttArea
            height: 300
            clip: true
            width: 450
            anchors.centerIn: parent
    
            color: backgroundColor
    
            ListView{
                id: ganttNameView // vertical List with Names and Gantt Ranges
    
                anchors.fill: parent
    
                interactive: false
                contentY: ganttView.contentY
                model: taskModel
                delegate: Rectangle{
                    width: ganttNameView.width
                    height: barHeight
                    Rectangle{
                        color: backgroundColor
                        width: parent.width
                        height: innerBarHeight
                        Text{
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.left: parent.left
                            text: taskName
                        }
                    }
                }
    
                Rectangle{
                    id: rangeArea
    
                    height: parent.height
                    width: parent.width - taskInfoWidth
                    x: taskInfoWidth
                    color: backgroundColor
    
                    ScrollView{ // Activity list
                        id: mainScroll
                        anchors.fill: parent
    
                        ListView{
                            id: ganttView
    
                            height: parent.height
                            contentWidth: fullGanttSpace
                            model: taskModel
    
                            delegate: Rectangle{
                                width: ganttView.width
                                height: barHeight
    
                                color: backgroundColor
    
                                Repeater {
                                    model: ranges
                                    Rectangle {
                                        x: model.start
                                        y: height / 2.0
    
                                        width: model.duration
                                        height: innerBarHeight/2.0
    
                                        border.width: 1
                                        color: "lightblue"
                                    }
                                }
    
    
                                Shape {
                                    ShapePath {
                                        strokeColor: "green"
                                        strokeWidth: 2
    
                                        startX: posInTime
                                        startY: 0
    
                                        PathLine { x: posInTime; y: ganttView.height }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    

    my simple TaskSimulation.qml - so that main.qml can be mostly visual oriented
    its not part of the question but needed to run my sample

    import QtQuick 2.15
    
    // Simulates fix amount of Tasks and their activity (random sleep and work)
    
    Item
    {
        id:taskSimulation
    
        //public properties:
    
        property ListModel taskModel: taskModel
        property int ticks: 0
        property int taskCount: 0
        property int intervalInMsec: 100
    
        //private stuff:
    
        ListModel {
            id: taskModel
            //[taskName, ranges{[{start, duration},...]},...]
        }
    
    
        ListModel {
            id: simModel
        }
    
        function getRandomInt(min, max) {
            min = Math.ceil(min);
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
    
        readonly property int openState: 0
        readonly property int closeState: 1
    
        function start()
        {
            for (var i = 0; i < taskCount; i++)
            {
                var ranges = []
                taskModel.append({"taskName": "Task"+i.toString(), "ranges":ranges});
                simModel.append({"waitFor": openState, "wait":getRandomInt(3,5)});
            }
            simTimer.running = true
        }
    
        function proceed()
        {
            for (var i = 0; i < taskModel.count; i++)
            {
                var sim = simModel.get(i);
    
                //console.log("task: "+i)
                //console.log("  wait: "+sim.wait)
                //console.log("  waitFor: "+(sim.waitFor === closeState ? "close":"open"))
    
                var task = taskModel.get(i)
                var task_ranges = task.ranges
                //console.log("  ranges: "+task_ranges.count)
    
                sim.wait = sim.wait - 1;
                if(sim.wait === 0)
                {
                    if( sim.waitFor === closeState)
                    {
                        //console.log("range closed: "+pos)
                        sim.waitFor = openState;
                    }
                    else if( sim.waitFor === openState)
                    {
                        //console.log("append range at pos: "+pos+" duration: 0!")
                        task_ranges.append({"start":ticks, "duration":0})
                        sim.waitFor = closeState;
                    }
                    sim.wait = getRandomInt(10,25);
                }
                else
                {
                    if( sim.waitFor === closeState)
                    {
                        var rangeCount = task_ranges.count
                        if(rangeCount > 0)
                        {
                            var range = task_ranges.get(rangeCount-1)
                            var duration = range.duration
                            var new_duration = duration+1
                            //console.log("extend range duration: "+new_duration)
                            range.duration = new_duration
                        }
                    }
                }
            }
        }
    
        Timer {
            id: simTimer
            interval: intervalInMsec
            running: false
            repeat: true
            onTriggered: {
                ticks = ticks + 1
                proceed()
            }
        }
    }
    

    short term goals:
    -fix that QtQuick 1.1/2.14 problem with the vertical scrollbar
    -also get a vertical scrollbar on the names list (if names are too big)
    -understand QML needs better - i always get something to work but it most of the time feel not elegant or clean

    my longterm goals:
    -automatic move (jump) of the gantt view if the timeline comes near the left side: https://streamable.com/xxhof3

    thanks for any help, QML-newbie programming/style etc. tips


  • Moderators



  • i've already tried an ScrollBar.horizontal: ScrollBar { } in my mainScroll or ganttView, - i can just carry the small scrollbar button around to no effect, no idea what im doing wrong - small examples work, but integrating these test does show no difference

    i think my ScrollView/ListView combination is maybe someway (bindings?) broken


  • Moderators

    @LowLevelM
    here are somehints/thoughts:

    • ScrollView is from QuikcControls1 (ScrollBar wont work here)
    • your ganttview doesnt have a width set. Try to set the clip property to true, it might clear things up visually


  • ScrollView is from QuikcControls1 (ScrollBar wont work here)

    i don't understand that tip - thats why i switched to "import QtQuick.Controls 2.14" with the resulting in non functional horizontal scroll bar

    your ganttview doesnt have a width set. Try to set the clip property to true, it might clear things up visually

    i have not visual clipping problems - just the horizontal scrollbar isn't working when i switch to "import QtQuick.Controls 2.14"


  • Moderators

    @LowLevelM said in horizontal scrollbar get lost when switching from QtQuick.Controls 1.1 to 2.14?:

    i don't understand that tip - thats why i switched to "import QtQuick.Controls 2.14" with the resulting in non functional horizontal scroll bar

    i suggest to port all elements away from QC1 to QC2
    and since you wrote you also tried the scrollbar on that item

    @LowLevelM said in horizontal scrollbar get lost when switching from QtQuick.Controls 1.1 to 2.14?:

    i have not visual clipping problems - just the horizontal scrollbar isn't working when i switch to "import QtQuick.Controls 2.14"

    a ListView/Flickable draws its contents beyond its boundaries. setting clipping on will reveal that behavior.
    Also the contentWidth is not the actual width of the flickable item. The scrolbar needs the items size to calculate its size from the content size.



  • thanks for the tip with the scrollbar - i've re-read the documentation and worked out a very small QtQuick 2 + ScrollBars example - but now im missing mousewheel scrolling :(

    animated gif: https://pasteboard.co/Jt3asxq.gif

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import QtGraphicalEffects 1.0
    
    Item{
        id: myApp
    
        height: 600
        width: 600
    
        Item {
            id: ganttChart
            width: 400
            height: 400
            anchors.centerIn: parent
            clip: true
    
            property real taskNamesWidth: 100
    
            // runtime
            property real myContentHeight: 2 * ganttChart.height
            property real mytaskNamesContentWidth: 200
            property real myTaskRangesContentWidth: 500
    
            component FillRainbowGradient : LinearGradient
            {
                anchors.fill: parent
                start: Qt.point(0, 0)
                end: Qt.point(parent.width, parent.height)
                gradient: Gradient {
                    GradientStop { position: 0.000; color: Qt.rgba(1, 0, 0, 1) }
                    GradientStop { position: 0.167; color: Qt.rgba(1, 1, 0, 1) }
                    GradientStop { position: 0.333; color: Qt.rgba(0, 1, 0, 1) }
                    GradientStop { position: 0.500; color: Qt.rgba(0, 1, 1, 1) }
                    GradientStop { position: 0.667; color: Qt.rgba(0, 0, 1, 1) }
                    GradientStop { position: 0.833; color: Qt.rgba(1, 0, 1, 1) }
                    GradientStop { position: 1.000; color: Qt.rgba(1, 0, 0, 1) }
                }
            }
    
            Row
            {
                height: parent.height
                width: parent.width
    
                Item
                {
                    id: taskNames
                    width: ganttChart.taskNamesWidth
                    height: parent.height
                    clip: true
    
                    Rectangle
                    {
                        id: taskNamesContent
                        width: ganttChart.mytaskNamesContentWidth
                        height: ganttChart.myContentHeight
    
                        FillRainbowGradient {}
    
                        x: -hbarTaskNames.position * width
                        y: -vbar.position * height
                    }
    
                    ScrollBar {
                        id: hbarTaskNames
                        hoverEnabled: true
                        active: hovered || pressed
                        orientation: Qt.Horizontal
                        size: taskNames.width / taskNamesContent.width
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.bottom: parent.bottom
                    }
                }
    
                Item
                {
                    id: taskRanges
                    width: parent.width - taskNames.width
                    height: parent.height
                    clip: true
    
                    Rectangle
                    {
                        id: taskRangesContent
                        width: ganttChart.myTaskRangesContentWidth
                        height: ganttChart.myContentHeight
    
                        FillRainbowGradient {}
    
                        x: -hbarTaskRanges.position * width
                        y: -vbar.position * height
                    }
    
                    ScrollBar {
                        id: hbarTaskRanges
                        hoverEnabled: true
                        active: hovered || pressed
                        orientation: Qt.Horizontal
                        size: taskRanges.width / taskRangesContent.width
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.bottom: parent.bottom
                    }
                }
            }
    
            ScrollBar {
                id: vbar
                hoverEnabled: true
                active: hovered || pressed
                orientation: Qt.Vertical
                size: ganttChart.height / ganttChart.myContentHeight
                anchors.top: parent.top
                anchors.right: parent.right
                anchors.bottom: parent.bottom
            }
        }
    }
    

    do i need to use ListViews/ScrollViews instead of doing my own Item/Rectangle-Clipping, or is it possible to attach a MouseHandler for that? i really like to understand this MouseHandler stuff first - if possible at all



  • fixed it by adding

        ```
    

    MouseArea {
    anchors.fill: parent

          onWheel: {
            if (wheel.angleDelta.y > 0) {
              vbar.decrease()
            }
            else {
              vbar.increase()
            }
          }
        }
    
    
    to my ganttChart item

Log in to reply