Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Non-modal Drawer blocks shortcuts



  • Hello everyone,

    I am in Qt 5.15.1, I stumbled on an issue while using the Drawer item. I followed the example "Qt Quick Controls - Side Panel" . The idea is to create a non-modal drawer usable as a fixed side dock when the the width of the window is sufficient.

    Yet, I found out by trials and errors that Shortcut items, "shortcut" properties in Action andr more worrisome (for me) the "Alt+...." shortcuts in the ApplicationWindow.menuBar are unusable. If these are created as children of Drawer, no problem. If the drawer is not "visible", all shortcuts are working. The moment the non-modal drawer is "visible", the parent/ancestors' shortcuts are lost.

    I found a little workaround in adding context: Qt.ApplicationShortcut to Shortcut and coupling each Action with a Shortcut to use this property. Yet, the menuBar is still out of reach of shortcuts.

    I find strange that a non-modal Drawer blocks all its ancestors shortcuts. I know it's inheriting Popup behavior, but it makes using the Side Panel idea difficult.

    Any thought ? Any idea for a workaround ? Do I need to couple all shortcuts from Action or menus with the snippet below :

    Shortcut {  
          sequence: KeySequence.Save
          context: Qt.ApplicationShortcut 
          onActivated: saveAction.trigger()
    }
    

    Here is a working example, switch the visible property of the drawer to see the difference. Type Ctrl+A, Ctrl+B and Alt+F and read the result.

    import QtQuick.Window 2.15
    import QtQuick 2.15
    import QtQml 2.15
    import QtQuick.Controls 2.15
    
    ApplicationWindow {
        id: base
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    
        Drawer {
            id: leftDrawer
            parent: base
    
            visible: true // switch it to false
            width: 200
            height: base.height
            modal: false
            interactive: false
            edge: Qt.LeftEdge
    
            Rectangle{
                color: "red"
            }
    
            Action {
                shortcut: "Ctrl+B"
                onTriggered: {
                    console.log("Ctrl+B")
    
                }
            }
    
        }
    
    
        Action {
    
            shortcut: "Ctrl+A"
            onTriggered: {
                console.log("Ctrl+A")
    
            }
        }
    
        menuBar: MenuBar{
    
            Menu {
                id: fileMenu
                title: qsTr("&File")
                MenuItem{
                    text: "Save"
    
                }
            }
        }
    
    }
    

    Thank you for your interest !



  • To avoid using Drawer, I created my own. I hope this will help someone !

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import QtQml 2.15
    
    Item {
        id: root
        default property alias contents : container.data
    
        property bool interactive : false
        property double position : 1.0
        property int edge : 0
        property bool isVisible: false
    
    
        z:1
    
        height: parent.height
        width: parent.width
        y: 0
    
        onIsVisibleChanged: {
            isVisible ? position = 1.0 : position = 0
        }
    
        Component.onCompleted: {
            container.children[0].anchors.fill = container
    
            if(state === "right_edge"){
                root.x = (root.parent.width - root.width) + (root.width * (1 - position))
            }
        }
    
        Behavior on position {
            NumberAnimation{
                easing.type: Easing.InQuad
                duration: 200
            }
        }
    
        function open(){
            position = 1.0
        }
    
        Item{
            id: leftFeelingZone
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.right: parent.left
            width: 10
    
            visible: edge === Qt.RightEdge && interactive
    
            TapHandler{
                id: leftTapHandler
                enabled: interactive && root.position === 0
    
                onTapped: {
                    root.position = 1.0
                }
                // grab:
                dragThreshold: 0
                margin: 5
                onGrabChanged: {
                    root.position = 1.0
                }
            }
        }
    
        FocusScope {
            id: dockBase
            anchors.fill: parent
    
    
    
            Rectangle {
                id: backgroundRectangle
                color: "white"
                anchors.fill: parent
    
    
    
                Item {
                    id: container
                    anchors.fill: parent
                }
            }
    
            onActiveFocusChanged: {
                if(!activeFocus && root.interactive && root.position === 1.0 ){
                    console.log("!activeFocus")
                    root.position = 1.0
                }
            }
        }
    
        Item{
            id: rightFeelingZone
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.left: parent.right
            width: 10
    
            visible: edge === Qt.LeftEdge && interactive
    
    
            TapHandler{
                id: rightTapHandler
                enabled: interactive && root.position === 0
    
                onTapped: {
                    console.log("rightTapHandler")
                    root.position = 1.0
                }
                // grab:
                dragThreshold: 0
                margin: 5
                onGrabChanged: {
                    root.position = 1.0
                }
    
    
            }
    
    
    
        }
    
        Connections {
            enabled: state === "right_edge"
            target: root.parent
            function onWidthChanged(){
                root.x = (root.parent.width - root.width) + (root.width * (1 - position))
            }
        }
    
        onWidthChanged: {
            if(state === "right_edge"){
                root.x = (root.parent.width - root.width) + (root.width * (1 - position))
            }
        }
    
        onPositionChanged: {
            if(state === "left_edge"){
                root.x = 0 - (root.width * (1 - position))
    
            }
            if(state === "right_edge"){
                root.x = (root.parent.width - root.width) + (root.width * (1 - position))
            }
    
            if(position === 0.0){
                isVisible = false
    
            }
            else if(position === 1.0){
                isVisible = true
            }
    
            dockBase.visible = position > 0.0
        }
    
    
    
        states: [
            State{
                name: "left_edge"
                when: root.edge === Qt.LeftEdge
    
    
    
            },
            State{
                name: "right_edge"
                when: root.edge === Qt.RightEdge
    
    
    
            }
    
        ]
    
    
    
    
        Item{
            id: overlayLayer
            parent: Overlay.overlay
            visible: root.interactive && root.position === 1.0
            height: root.height
            y: Overlay.overlay.mapToItem(root.parent, root.x, root.y).y
    
    
    
    
            TapHandler {
                id: overlayTapHandler
    
                enabled: root.interactive && root.position === 1.0
    
                onTapped: {
                    console.log('overlay pressed')
                    root.position = 0.0
                    eventPoint.accepted = false
                }
    
            }
    
    
    
    
            states: [
                State{
                    name: "left_edge"
                    when: root.edge === Qt.LeftEdge
                    PropertyChanges {
                        target: overlayLayer
                        x: Overlay.overlay.mapToItem(root.parent, root.width, root.y).x
                        width: Overlay.overlay.width - root.width
    
                    }
    
    
                },
                State{
                    name: "right_edge"
                    when: root.edge === Qt.RightEdge
                    PropertyChanges {
                        target: overlayLayer
                        x: Overlay.overlay.mapToItem(root.parent, 0, 0).x
                        width: Overlay.overlay.width - root.width
    
                    }
    
    
                }
    
    
            ]
        }
    
    
    }
    
    


  • I reported the bug to Qt : https://bugreports.qt.io/browse/QTBUG-86801


Log in to reply