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

Get only topmost object's event when using general event filter



  • Hi!

    I have a problem with the way TextField handles "blur" events. On most applications, when you click outside of a text input, the text input loses focus. In QML, the input will keep the focus when you click outside of it.

    I haven't found a signal/method/etc. to get notified when the user clicks outside of my input in order to un-focus it.

    One solution would be to overload most of the items I use in my app (Item, Rectangle, etc.) to generate an event when clicked and unfocus the inputs when this happens, but this forces me to do a lot of changes in my code base.

    The other solution I am trying right now is to install an event filter on my QGuiApplication and, for each event, find if the clicked element has focus (or if any of its parent has focus). If none has focus and the current element having focus is an input, I remove the focus.

    My problem is that for each click, I get multiple events instead of one. The only one I am interested in is the one generated by the top-most item (the one I clicked).

    ex: I click on my TextField and I get the following events generated:

    Should remove focus for ApplicationWindowMain_QMLTYPE_232(0x563ff62cbb80) 0x7fffcc3af590 
    Should remove focus for QQuickMouseArea_QML_93(0x563ff9c28790) 0x7fffcc3af590 
    Should keep focus for TextField_QMLTYPE_84_QML_85_QML_91(0x563ff9c235c0) 0x7fffcc3af590
    

    The only one I am interested in is the last one (Where I correctly detect that I should keep focus). But I receive other event that would make me remove focus.

    Since I do not know how many events I will receive, I can't ignore the first ones.

    Is there a way to know which item generated the actual event (ie: the topmost item) instead of having all items in my hierarchy send an event ?

    Thanks


  • Qt Champions 2018

    An other solution would be to check on a press if the active focus item of the window is under the press.

    This can even be done in pure QML, by placing a MouseArea on top of everything and discarding the events:

    MouseArea {
        parent: Window.contentItem
        anchors.fill: parent
        z: Overlay.overlay.z + 1
        onPressed: mouse => {
            mouse.accepted = false;
            const activeFocusItem = Window.window.activeFocusItem;
            if (activeFocusItem && !activeFocusItem.contains(mapToItem(activeFocusItem, mouse.x, mouse.y)))
                activeFocusItem.focus = false;
        }
    }

  • Qt Champions 2018

    An other solution would be to check on a press if the active focus item of the window is under the press.

    This can even be done in pure QML, by placing a MouseArea on top of everything and discarding the events:

    MouseArea {
        parent: Window.contentItem
        anchors.fill: parent
        z: Overlay.overlay.z + 1
        onPressed: mouse => {
            mouse.accepted = false;
            const activeFocusItem = Window.window.activeFocusItem;
            if (activeFocusItem && !activeFocusItem.contains(mapToItem(activeFocusItem, mouse.x, mouse.y)))
                activeFocusItem.focus = false;
        }
    }


  • This works great and is simpler than my other solutions. Thanks!


Log in to reply