Search code examples
qtfocusqmlqtquick2

With QtQuick.Controls 1.4, how to prevent focus change when mouse goes on ComboBox or SpinBox Item?


I use a ListView and inside each Item of this ListView, I have a ComboBox or a SpinBox.

My problem is that when I want to scroll my ListView, if my mouse goes on a ComboBox or a SpinBox, the focus will change and the scroll will now be on this Item instead of the list.

I would like that focus is set on these Item only if I click on them.

Code example:

import QtQuick.Controls 1.4

ListView {
    id: list
    ScrollBar.vertical: ScrollBar {}
    ...
    model: DelegateModel {
        id:delegate
        model: myModel
        delegate : Rectangle {
             id: rect
             ...
             SpinBox {
                 id: spin 
                 ...
             }
        }     
    }
}

How could I proceed ?


Solution

  • This is a common problem with the old QtQuick.Controls 1.x components, that they greedily grab the mouse events. To my knowledge, there is no official way to prevent this.

    Here you find a solution, on how to overlay a such a component (in this case a Slider) with a MouseArea that prevents that misbehaviour.

    Alternatively you might switch to the new QtQuick.Controls 2.x-Spinbox. As this has a different default look, you might need to adjust it, to look (more) similar to the old one. Here you can find a description on how you can do this.

    Remember that it is easy to have both: QtQuick.Controls 1.x and QtQuick.Controls 2.x in one file, by importing them with aliases.

    Digging into the source of the QtQuick.Controls 1.4 we can find also a hacky solution.

    Relevant Files:

    We can see, a SpinBox is a Control. The SpinBox has a child MouseArea, which handles the onWheel-event. We're gonna disable this MouseArea. To access it, we need to know the index in the SpinBox.children. We see in Control that there are two Loader as children (Index 0 and 1). In SpinBox we have two other children before the MouseArea (Index 2 and 3) -> So we need to set idOfSpinBox.children[4].enabled = false to disable the wheel-sensitivity.

    import QtQuick 2.7
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        id: root
        visible: true
        width: 800
        height: 600
    
        ListView {
            model: 20
            width: 100
            height: 200
            delegate: SpinBox {
                Component.onCompleted: children[4].enabled = false
            }
        }
    }
    

    or if we want to have the scroll wheel enabled, when the SpinBox was clicked, we use:

    delegate: SpinBox {
        id: spinBox
        Component.onCompleted: children[4].enabled = Qt.binding(function() { return spinBox.activeFocus } )
    }
    

    But then we need to find some way to lose this focus again.