Fix keypad navigation within a button group for push buttons

Keypad navigation within a group should work for auto-exclusive buttons,
or for checkable buttons that are in a button group. Since the code
already tests whether the button should be treated like an exclusive
(which implies checkable) button, use the result of that test when
finding the candidate button to move focus to, and not only when
actually changing the checked button and the focus.

Change-Id: I4dc41a90d51a8304483046252ceff0ebfe2a2e52
Fixes: QTBUG-27151
Done-with: david.faure@kdab.com
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
bb10
Volker Hilsheimer 2020-03-10 14:37:15 +01:00
parent 40f4b3de1a
commit e7cff5bca7
2 changed files with 70 additions and 2 deletions

View File

@ -246,7 +246,7 @@ void QAbstractButtonPrivate::notifyChecked()
void QAbstractButtonPrivate::moveFocus(int key)
{
QList<QAbstractButton *> buttonList = queryButtonList();;
QList<QAbstractButton *> buttonList = queryButtonList();
#if QT_CONFIG(buttongroup)
bool exclusive = group ? group->d_func()->exclusive : autoExclusive;
#else
@ -266,7 +266,7 @@ void QAbstractButtonPrivate::moveFocus(int key)
for (int i = 0; i < buttonList.count(); ++i) {
QAbstractButton *button = buttonList.at(i);
if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() &&
(autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
(exclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0)));
QPoint p = buttonRect.center();

View File

@ -83,6 +83,7 @@ Q_OBJECT
private slots:
void arrowKeyNavigation();
void keyNavigationPushButtons();
void exclusive();
void exclusiveWithActions();
void testSignals();
@ -185,6 +186,73 @@ void tst_QButtonGroup::arrowKeyNavigation()
QVERIFY(bt3.hasFocus());
}
/*
Test that tab and arrow key navigation through buttons
in an invisible button group works as expected. Tabbing
into the group should give focus to the checked button,
and arrow navigation should change the checked button and
move focus.
*/
void tst_QButtonGroup::keyNavigationPushButtons()
{
if (!qt_tab_all_widgets())
QSKIP("This test requires full keyboard control to be enabled.");
QDialog dlg(nullptr);
QLineEdit *le1 = new QLineEdit;
le1->setObjectName("le1");
QPushButton *pb1 = new QPushButton("Exclusive 1");
pb1->setObjectName("pb1");
pb1->setCheckable(true);
pb1->setChecked(true);
QPushButton *pb2 = new QPushButton("Exclusive 2");
pb2->setObjectName("pb2");
pb2->setCheckable(true);
QPushButton *pb3 = new QPushButton("Exclusive 3");
pb3->setObjectName("pb3");
pb3->setCheckable(true);
QLineEdit *le2 = new QLineEdit;
le2->setObjectName("le2");
QVBoxLayout* layout = new QVBoxLayout(&dlg);
layout->addWidget(le1);
layout->addWidget(pb1);
layout->addWidget(pb2);
layout->addWidget(pb3);
layout->addWidget(le2);
QButtonGroup *buttonGroup = new QButtonGroup;
buttonGroup->addButton(pb1);
buttonGroup->addButton(pb2);
buttonGroup->addButton(pb3);
dlg.show();
qApp->setActiveWindow(&dlg);
if (!QTest::qWaitForWindowActive(&dlg))
QSKIP("Window activation failed, skipping test");
QVERIFY2(le1->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Tab);
QVERIFY2(pb1->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QVERIFY2(pb1->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Down);
QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Down);
QVERIFY2(pb3->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QVERIFY2(pb3->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Up);
QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Tab);
QVERIFY2(le2->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Backtab);
QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName()));
QTest::keyClick(qApp->focusWidget(), Qt::Key_Backtab);
QVERIFY2(le1->hasFocus(), qPrintable(qApp->focusWidget()->objectName()));
}
void tst_QButtonGroup::exclusiveWithActions()
{
QDialog dlg(0);