Thanks for the reply, Andrew.

It looks like the contentItem of QQuickWindow is already a focus scope [1]:

    contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope;

Shouldn’t that already work, then?

If I set QT_LOGGING_RULES= qt.quick.focus=true, and use the following example, 
I get the output below:

http://pastebin.com/X9JMcpGh

This is printed when the application has started:

      qt.quick.focus: QQuickWindowPrivate::setFocusInScope():
      qt.quick.focus:     scope: QQuickRootItem(0x1e25bec0000)
      qt.quick.focus:     scopeSubFocusItem: QObject(0x0)
      qt.quick.focus:     item: QQuickFocusScope_QML_0(0x1e25bec66c0)
      qt.quick.focus:     activeFocusItem: QObject(0x0)
      qt.quick.focus: QQuickWindowPrivate::setFocusInScope():
      qt.quick.focus:     scope: QObject(0x0)
      qt.quick.focus:     item: QQuickRootItem(0x1e25bec0000)
      qt.quick.focus:     activeFocusItem: QObject(0x0)
      qml: activeFocusItem QQuickFocusScope_QML_0(0x1e25bec66c0)

This is printed when I open the menu:

      qt.quick.focus: QQuickWindowPrivate::setFocusInScope():
      qt.quick.focus:     scope: QQuickToolBar(0x1e25bec2dc0)
      qt.quick.focus:     scopeSubFocusItem: QObject(0x0)
      qt.quick.focus:     item: QQuickToolButton(0x1e25bec2a60)
      qt.quick.focus:     activeFocusItem: QQuickFocusScope_QML_0(0x1e25bec66c0)
      qt.quick.focus: QQuickWindowPrivate::setFocusInScope():
      qt.quick.focus:     scope: QQuickRootItem(0x1e25bec0000)
      qt.quick.focus:     scopeSubFocusItem: 
QQuickFocusScope_QML_0(0x1e25bec66c0)
      qt.quick.focus:     item: QQuickToolBar(0x1e25bec2dc0)
      qt.quick.focus:     activeFocusItem: QQuickFocusScope_QML_0(0x1e25bec66c0)
      qml: activeFocusItem QQuickToolButton(0x1e25bec2a60)
      qml: @@@@@@@@@ clicked menu toolbutton
      qt.quick.focus: QQuickWindowPrivate::setFocusInScope():
      qt.quick.focus:     scope: QQuickRootItem(0x1e25bec0000)
      qt.quick.focus:     scopeSubFocusItem: QQuickToolBar(0x1e25bec2dc0)
      qt.quick.focus:     item: QQuickPopupItem(0x1e25bec29a0)
      qt.quick.focus:     activeFocusItem: QQuickToolButton(0x1e25bec2a60)
      qml: activeFocusItem QQuickPopupItem(0x1e25bec29a0)

And this is printed when I close the menu:

      qt.quick.focus: QQuickWindowPrivate::clearFocusInScope():
      qt.quick.focus:     scope: QQuickRootItem(0x1e25bec0000)
      qt.quick.focus:     item: QQuickPopupItem(0x1e25bec29a0)
      qt.quick.focus:     activeFocusItem: QQuickPopupItem(0x1e25bec29a0)
      qml: activeFocusItem QQuickRootItem(0x1e25bec0000)
      qml: @@@@@@@@@ closed menu

If I apply the following patch to qtquickcontrols2, the root item becomes the 
active focus item, and so pressing alt does nothing:

      diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp 
b/src/quicktemplates2/qquickapplicationwindow.cpp
      index 401313d..cb8a2fa 100644
      --- a/src/quicktemplates2/qquickapplicationwindow.cpp
      +++ b/src/quicktemplates2/qquickapplicationwindow.cpp
      @@ -424,6 +424,7 @@ QQuickItem *QQuickApplicationWindow::contentItem() 
const
            QQuickApplicationWindowPrivate *d = 
const_cast<QQuickApplicationWindowPrivate *>(d_func());
            if (!d->contentItem) {
                  d->contentItem = new QQuickItem(QQuickWindow::contentItem());
      +            d->contentItem->setFlag(QQuickItem::ItemIsFocusScope);
                  d->relayout();
            }
            return d->contentItem;

[1] 
http://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quick/items/qquickwindow.cpp#n483


From: Andrew den Exter [mailto:[email protected]]
Sent: Friday, 6 May 2016 1:38 PM
To: Mitch Curtis <[email protected]>
Cc: [email protected]
Subject: Re: [Development] [Qt Quick] Automatically restoring focus to last 
focused item

That's a very universal solution to a specific problem and one that's going to 
have all kinds of unintended consequences. Without knowing why focus was taken 
from an item and given to another and why that other object relinquished focus 
it's impossible to know whether focus should be restored to that first item.  
That memory may have to go back more than one item as well, after all if you 
open one menu then another then the previous focus item is the first window and 
that's obviously not what you want to give focus to.

What you want to do instead is introduce a FocusScope to ApplicationWindow. If 
the window's content item is a focus scope then giving focus to a menu which is 
outside of this scope will not affect focus within the scope, then whatever 
logic closes the menu can give focus back to the content item and that will 
implicitly return active focus to your item in the window body.


Andrew


On Fri, May 6, 2016 at 12:08 AM, Mitch Curtis 
<[email protected]<mailto:[email protected]>> wrote:
Consider the example below (requires Qt 5.7):

    import QtQuick 2.6
    import QtQuick.Layouts 1.1
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.0

    ApplicationWindow {
        width: 400
        height: 200
        visible: true

        onActiveFocusItemChanged: print("activeFocusItem", activeFocusItem)

        header: ToolBar {
            RowLayout {
                focus: false
                implicitWidth: children[0].implicitWidth
                implicitHeight: children[0].implicitHeight

                ToolButton {
                    text: qsTr("File")
                    onClicked: fileMenu.open()

                    Menu {
                        id: fileMenu
                        y: parent.height

                        MenuItem {
                            text: qsTr("New")
                        }
                        MenuItem {
                            text: qsTr("open")
                        }
                        MenuItem {
                            text: qsTr("Close")
                        }
                    }
                }
            }
        }

        FocusScope {
            id: focusScope
            focus: true
            anchors.fill: parent

            property bool toggled: false
            onToggledChanged: print("toggled", toggled)

            Keys.onPressed: {
                if (event.modifiers === Qt.AltModifier) {
                    focusScope.toggled = true;
                }
            }
            Keys.onReleased: {
                if ((event.modifiers === Qt.AltModifier || event.key === 
Qt.Key_Alt) && !event.isAutoRepeat) {
                    focusScope.toggled = false;
                }
            }

            RowLayout {
                anchors.centerIn: parent

                Button {
                    id: penButton
                    text: qsTr("Pen")
                    highlighted: !focusScope.toggled
                }
                Button {
                    id: eyedropperButton
                    text: qsTr("Eyedropper")
                    highlighted: focusScope.toggled
                }
            }
        }
    }

The idea is that holding the Alt key down will toggle between two "modes". The 
mode is indicated by a highlighted button.

Try switching between the buttons. Now open the menu by clicking the "File" 
button. The menu will receive focus and the focus scope will lose it. If you 
then close the menu and try to switch between the buttons again, it won't work 
because the focus scope never regained focus (the root item now has it). This 
is explained here [1]:

"When a QML Item explicitly relinquishes focus (by setting its focus property 
to false while it has active focus), the system does not automatically select 
another type to receive focus. That is, it is possible for there to be no 
currently active focus."

I'm not sure if "explicitly relinquishes focus" is exactly what's happening 
here, though. The FocusScope loses focus because something else was open 
temporarily. So now the developer has no other option than to listen to e.g. 
the menu visibility changes and explicitly set focus on the FocusScope 
accordingly. That's pretty gross if you ask me. I think we can do better. 
Specifically, I think that we should remember the last focused item, and give 
that focus, rather than give it to the root item. The question is, would it be 
an acceptable change for Qt 5? I'd assume that users are already working around 
this anyway, and so the fix wouldn't hurt.

[1] http://doc.qt.io/qt-5/qtquick-input-focus.html
_______________________________________________
Development mailing list
[email protected]<mailto:[email protected]>
http://lists.qt-project.org/mailman/listinfo/development

_______________________________________________
Development mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to