qtqmlqtquick2qtquickcontrolsqtquickextras

How to change the colour of selected item in Tumbler


I am trying to familiarise myself with QML and was looking at the nice example involving TumblerColumn. I have a simple spinner column as:

TumblerColumn {
        id: yearColumn
        width: characterMetrics.width * 4 + tumbler.delegateTextMargins

        model: ListModel {
            Component.onCompleted: {
                for (var i = tumbler.startYear; i < tumbler.endYear; ++i) {
                    append({value: i.toString()});
                }
            }
       }
}

Now I would like to change the colour of the currently selected item. I tried to use the highlight property but could not get it to work. Is this easy to do?


Solution

  • Taking the code from the same example, you can define your own TumblerStyle:

    style: TumblerStyle {
        id: tumblerStyle
    
        delegate: Item {
            implicitHeight: (tumbler.height - padding.top - padding.bottom) / tumblerStyle.visibleItemCount
    
            Text {
                id: label
                text: styleData.value
                color: styleData.current ? "red" : "#666666"
                opacity: 0.4 + Math.max(0, 1 - Math.abs(styleData.displacement)) * 0.6
                anchors.centerIn: parent
            }
        }
    }
    

    I took this code from the Base TumblerStyle. It adds a check for the current item, turning it red if it is current:

    color: styleData.current ? "red" : "#666666"
    

    Here's a list of other styleData properties available within delegate.

    Minimal example:

    import QtQuick 2.4
    import QtQuick.Window 2.0
    import QtQuick.Controls 1.2
    import QtQuick.Controls.Styles 1.2
    import QtQuick.Extras 1.2
    
    Window {
        id: root
        width: 600
        height: 400
        visible: true
    
        Tumbler {
            id: tumbler
            anchors.centerIn: parent
    
            TextMetrics {
                id: characterMetrics
                font.bold: true
                text: "M"
            }
    
            readonly property real delegateTextMargins: characterMetrics.width * 1.5
            readonly property var days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    
            TumblerColumn {
                id: tumblerDayColumn
    
                function updateModel() {
                    var previousIndex = tumblerDayColumn.currentIndex;
                    var newDays = tumbler.days[monthColumn.currentIndex];
    
                    if (!model) {
                        var array = [];
                        for (var i = 0; i < newDays; ++i) {
                            array.push(i + 1);
                        }
                        model = array;
                    } else {
                        // If we've already got days in the model, just add or remove
                        // the minimum amount necessary to make spinning the month column fast.
                        var difference = model.length - newDays;
                        if (model.length > newDays) {
                            model.splice(model.length - 1, difference);
                        } else {
                            var lastDay = model[model.length - 1];
                            for (i = lastDay; i < lastDay + difference; ++i) {
                                model.push(i + 1);
                            }
                        }
                    }
    
                    tumbler.setCurrentIndexAt(0, Math.min(newDays - 1, previousIndex));
                }
            }
            TumblerColumn {
                id: monthColumn
                width: characterMetrics.width * 3 + tumbler.delegateTextMargins
                model: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
                onCurrentIndexChanged: tumblerDayColumn.updateModel()
            }
            TumblerColumn {
                id: yearColumn
                width: characterMetrics.width * 4 + tumbler.delegateTextMargins
                model: ListModel {
                    Component.onCompleted: {
                        for (var i = 2000; i < 2100; ++i) {
                            append({value: i.toString()});
                        }
                    }
                }
            }
    
            style: TumblerStyle {
                id: tumblerStyle
    
                delegate: Item {
                    implicitHeight: (tumbler.height - padding.top - padding.bottom) / tumblerStyle.visibleItemCount
    
                    Text {
                        id: label
                        text: styleData.value
                        color: styleData.current ? "red" : "#666666"
                        opacity: 0.4 + Math.max(0, 1 - Math.abs(styleData.displacement)) * 0.6
                        anchors.centerIn: parent
                    }
                }
            }
        }
    }