QML Controls 1.x ComboBox.onWheel Event & Flickable

If you place a ComboBox on a Flickable, you may unhappily notice that ComboBox steals your mouse wheel events on Flickable.

I think an UI component like ComboBox which accepts mouse wheel event is totally a stupid idea and a great anti-pattern of UI/UX (the value of ComboBox is quite easily to be accidently modified). However, the API of QtQuick Controls, no matter 1 or 2, are totally moron. They totally don’t provide any API to deal with a lot of shit. So you have to workaround it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// MyComboBox.qml
import QtQuick 2.6
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls.Private 1.0
ComboBox {
id: root
property Item _flickableItem
Component.onCompleted: {
var p = root
while (!p.flick) { // no .flick()
//console.log(p.toString(), p.flick)
p = p.parent
if (!p) {return}
}
//console.log(">>", p.toString(), p.flick)
root._flickableItem = p
}
...
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: mouse.accepted = false
onReleased: mouse.accepted = false
onClicked: mouse.accepted = false
onDoubleClicked: mouse.accepted = false;
onPressAndHold: mouse.accepted = false;
onWheel: {
if (root._flickableItem) {
root._flickableItem.flick(0, wheel.angleDelta.y * 5)
}
}
}
}

Explanation

  1. When component is loaded and instantialized (Component.onCompleted), use a while loop find any parent component has flick attribute. If found, assign _flickableItem property as it.
  2. Place a MouseArea to “steal the wheels events back”, which invoke _flickableItem.flick() when onWheel.