Search code examples
qtlistviewqmlscrollviewqtquick2

How to add mousewheel scrolling to the vertical scrollbar or scrolled area?


this is the first time in months that i touch QML again (im mainly a C++ backend/alogrithm developer) to write a small frontend for some sort of scheduling algorithm

  • i have a good understanding of the QML model/property/item system and javascript interaction
  • im in love with the QML feature beeing able to build a working/living frontend without even touching C++ :)
  • im feeling nearly helpless when it comes to all the possible solutions in combining deeply nested rectangles/listviews/scrollviews and all the (latend) changes from quick 1 to quick 2

this is my dirty QtQuick 1.1 prototype of the chart - to get an idea what i want to reach

enter image description here

  • on the left is a list with task names
  • to the right are the typical gantt chart ranges showing the tasks activity
  • the green line is a time-axis that gets triggered by the simulation
  • the sample contains a timer based simulation with a fixed amount of tasks simulating (infinite) activity

schema of/requirements the gantt-chart: enter image description here

  • the task-names can be bigger than 150 - then a bottom hscrollbar should appear for the names
  • the ranges can be bigger then than 400 - then a bottom hscrollbar should appear for the ranges
  • the vscrollbar on the right should appear when tasks hight > 500, should scroll the task-names and ranges together
  • vertical scrolling should work with mousewheel
  • no bouncing

and this is my current clean mini test for getting everything ready enter image description here

my rainbows.gml

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
        }
    }
}

question:

what is needed to allow vertical scrolling with the mousewheel? do i need to use ScrollViews or a ListView for that or is there a way to attach a MouseHandler?

thanks for any help and tips


Solution

  • You could use a MouseArea.

    Put it above your ganttChart and use the wheel signal to scroll your vertical scrollbar.


    Your code could look something like this:

    MouseArea {
        anchors.fill: ganttChart
    
        onWheel: {
            if (wheel.angleDelta.y > 0) {
                vbar.decrease()
            }
            else {
                vbar.increase()
            }
        }
    }