Search code examples
qmlqtquick2qtquickcontrolsstackview

key handling in a StackView with multiple items


I have a StackView with two items in it. Both items should handle some keys.

I would assume that, if the currentItem in a StackView does not handle a key, that the key would be forwarded to the lower layers but apparently, this is not the case.

The following example illustrates the problem. When pressing eg 'A', I see that the key is handled by layer1 and by the stackview itself but the key is not handled by layer0.

Note that layer0 remains visible after pushing layer1 on top of it due to the properties.exitItem.visible = true statement in transitionFinished

import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.Controls 1.4

Window {
    id: mainWindow
    visible: true
    width: 1280
    height: 720
    color: "black"

    Component {
        id: layer0
        Rectangle {
            focus:true
            width:200;height:200;color:"red"
            Keys.onPressed: console.log("layer0")
        }
    }
    Component {
        id: layer1
        Rectangle {
            focus:true
            width:200;height:200;color:"#8000FF00"
            Keys.onPressed: console.log("layer1")
        }
    }

    StackView {
        id: stack
        width: parent.width
        height: parent.height
        focus: true

        Component.onCompleted: {
            stack.push(layer0)
            stack.push(layer1).focus=true
        }

        Keys.onPressed: {
            console.log("StackView.onPressed")
        }

        delegate: StackViewDelegate {
            function transitionFinished(properties)
            {
                properties.exitItem.visible = true
                properties.exitItem.focus = true
            }
        }
    }
}

Solution

  • I would assume that, if the currentItem in a StackView does not handle a key, that the key would be forwarded to the lower layers but apparently, this is not the case.

    Apparently according to Qt Documentation the key event propagation goes like this:

    If the QQuickItem with active focus accepts the key event, propagation stops. Otherwise the event is sent to the Item's parent until the event is accepted, or the root item is reached.

    If I understand that correctly, in your example the two items are siblings. Layer1 has focus, and it will propagate the event UP in the hierarchy, not horizontally or down. Moreover, those multiple focus: true won't have any effect, since the last item receiving the focus will get it, in this situation layer1 in Component.onCompleted

    One way to work around this could be defining a new signal, say,

    Window {
        id: mainWindow
        ...
        signal keyReceived(int key)
    

    and then in StackView to fire that event on Keys.onPressed:

        Keys.onPressed: {
            console.log("StackView.onPressed")
            keyReceived(event.key)
        }
    

    And finally catching the new signal in your Rectangles:

    Component {
        id: layer1
        Rectangle {
            Connections {
                target: mainWindow
                onKeyReceived: console.log("layer1")
            }
        }
    }