Return focus to correct widget after showing menu

By the time we call setKeyboardMode(true), the menu may
already have taken focus. This change sets keyboardFocusWidget
before opening the popup, and makes sure that keyboardFocusWidget
is not set to the popup. (We cannot remove the assignment from
setKeyboardMode(), since it's called from several places.)

[ChangeLog][QtWidgets] Fixed widget losing focus after showing
menu second time.

Task-number: QTBUG-56860
Change-Id: Ic01726bf694e6f365dd7b601ad555156e0fdf6c5
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Paul Olav Tvete 2017-08-23 11:48:11 +02:00
parent bc31d2235c
commit 35781b3588
2 changed files with 50 additions and 1 deletions

View File

@ -288,7 +288,7 @@ void QMenuBarPrivate::setKeyboardMode(bool b)
keyboardState = b;
if(b) {
QWidget *fw = QApplication::focusWidget();
if (fw != q)
if (fw && fw != q && fw->window() != QApplication::activePopupWidget())
keyboardFocusWidget = fw;
focusFirstAction();
q->setFocus(Qt::MenuBarFocusReason);
@ -1706,6 +1706,7 @@ void QMenuBarPrivate::_q_internalShortcutActivated(int id)
}
}
keyboardFocusWidget = QApplication::focusWidget();
setCurrentAction(act, true, true);
if (act && !act->menu()) {
activateAction(act, QAction::Trigger);

View File

@ -39,6 +39,7 @@
#include <qstyleoption.h>
#include <QVBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include <qscreen.h>
#include <qobject.h>
@ -106,6 +107,7 @@ private slots:
void allowActiveAndDisabled();
#endif
void taskQTBUG56860_focus();
void check_endKey();
void check_homeKey();
@ -710,6 +712,52 @@ void tst_QMenuBar::check_cursorKeys3()
}
#endif
void tst_QMenuBar::taskQTBUG56860_focus()
{
#if defined(Q_OS_DARWIN)
QSKIP("Native key events are needed to test menu action activation on macOS.");
#endif
QMainWindow w;
QMenuBar *mb = w.menuBar();
if (mb->platformMenuBar())
QSKIP("This test requires the Qt menubar.");
QMenu *em = mb->addMenu("&Edit");
em->setObjectName("EditMenu");
em->addAction("&Cut");
em->addAction("C&opy");
QPlainTextEdit *e = new QPlainTextEdit;
e->setObjectName("edit");
w.setCentralWidget(e);
w.show();
QApplication::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTRY_COMPARE(QApplication::focusWidget(), e);
// Open menu
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier );
QTRY_COMPARE(QApplication::activePopupWidget(), em);
// key down to trigger focus
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
// and press ENTER to close
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
QTRY_COMPARE(QApplication::activePopupWidget(), nullptr);
// focus should have returned to the editor by now
QTRY_COMPARE(QApplication::focusWidget(), e);
// Now do it all over again...
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier );
QTRY_COMPARE(QApplication::activePopupWidget(), em);
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
QTRY_COMPARE(QApplication::activePopupWidget(), nullptr);
QTRY_COMPARE(QApplication::focusWidget(), e);
}
/*!
If a popupmenu is active you can use home to go quickly to the first item in the menu.
*/