Creating QML Controls From Scratch: Slider

Chris Cortopassi

Chris Cortopassi


A seasoned engineer with 10+ years experience, Chris has expertise in desktop and embedded systems in larger, real-time multi-threaded applications, as well as experience using Qt-based software for complex projects within the motor control, telecommunications and civil engineering industries. 

By Chris Cortopassi | Wednesday, June 14, 2017

qmlscene

Continuing our QML Controls from Scratch series, this time we will implement a Slider. The Slider has value, minimum, and maximum public properties. Slider is implemented with a single MouseArea that covers the entire control and utilizes onPositionChanged to handle the user sliding the "pill" (the portion which the user moves ) left and right.

The background "tray" (a horizontal line, which can be tapped) is split into left and right pieces so that it doesn't show through the pill when enabled is set to false (since the pill is partially transparent in the disabled state). The only tricky parts about Slider are the equations to compute the value from pixels and pixels from the value.

Slider.qml

import QtQuick 2.0

Item { // Size controlled by height
    id: root
    
// public
    property real value:    0
    property real minimum:  0
    property real maximum: 10
   
// private
    width: 250;  height: 50  // Default size
    opacity: enabled? 1: 0.3 // Disabled state
    
    Repeater { // Left and right trays (so tray doesn't shine through pill in disabled state)
        model: 2
        
        Rectangle {
            x:     !index?               0: pill.x + pill.width - radius
            width: !index? pill.x + radius: root.width - x;  height: 0.1 * root.height
            radius: 0.5 * height
            color: 'black'
            anchors.verticalCenter: parent.verticalCenter
        }
    }
    
    Rectangle { // Pill
        id: pill
        x: (value - minimum) / (maximum - minimum) * (root.width - pill.width) // Pixels from value
        width: parent.height
        height: width
        border.width: 0.05 * root.height
        radius: 0.5 * height
    }
    
    MouseArea {
        anchors.fill: parent
        onPressed:          if (pill.x < mouse.x  &&  mouse.x < pill.x + pill.width) pill.opacity = 0.5 // Down state
        onReleased:           { pill.opacity = 1; setPixels(mouse.x) } // Tap
        onCanceled:            pill.opacity = 1            
        onPositionChanged:  if (pill.opacity < 1) setPixels(mouse.x) // Drag pill
    } 
    
    function setPixels(pixels) {
        var value = (maximum - minimum) / (root.width - pill.width) * (pixels - pill.width / 2) + minimum // value from pixels
        root.value = Math.min(Math.max(minimum, value), maximum)
    }
}

test.qml

Slider {
    value:     5
    onValueChanged: print('Slider onValueChanged', value)
    minimum: -10
    maximum:  10
}

Summary

In this post, we created a Slider. Next time we'll create a ScrollBar element. The source code can be downloaded from here.



Have a question or add to the conversation: Log in Register