QQuickTreeView: add keyboard navigation support

Override keyPressEvent in QQuickTreeView to let
the left and right arrow keys expand and collapse
the current row in the tree. Note that the application
developer can set keyNavigationEnabled to false if this
default behavior is not wanted.

Change-Id: If5201dafd1d3d7e2e4a113aeb2a60f601a1a4c35
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
Richard Moe Gustavsen 2022-04-07 10:07:28 +02:00
parent eb5ff13248
commit b23626d0b8
5 changed files with 97 additions and 1 deletions

View File

@ -571,6 +571,33 @@ QModelIndex QQuickTreeView::modelIndex(int column, int row) const
return modelIndex({column, row});
}
void QQuickTreeView::keyPressEvent(QKeyEvent *event)
{
event->ignore();
if (!keyNavigationEnabled())
return;
if (!selectionModel())
return;
const int row = cellAtIndex(selectionModel()->currentIndex()).y();
switch (event->key()) {
case Qt::Key_Left:
collapse(row);
event->accept();
break;
case Qt::Key_Right:
expand(row);
event->accept();
break;
default:
break;
}
if (!event->isAccepted())
QQuickTableView::keyPressEvent(event);
}
QT_END_NAMESPACE
#include "moc_qquicktreeview_p.cpp"

View File

@ -87,6 +87,9 @@ signals:
void expanded(int row, int depth);
void collapsed(int row, bool recursively);
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
Q_DISABLE_COPY(QQuickTreeView)
Q_DECLARE_PRIVATE(QQuickTreeView)

View File

@ -40,11 +40,12 @@
import QtQuick
import TestModel
Item {
Rectangle {
id: root
implicitWidth: padding + label.x + label.implicitWidth + padding
implicitHeight: label.implicitHeight * 1.5
color: current ? "lightgreen" : "white"
property alias text: label.text
@ -57,6 +58,7 @@ Item {
required property bool expanded
required property int hasChildren
required property int depth
required property bool current
TapHandler {
onTapped: treeView.toggleExpanded(row)

View File

@ -51,6 +51,7 @@ Item {
anchors.fill:parent
anchors.margins: 10
model: TestModel {}
selectionModel: ItemSelectionModel {}
clip: true
delegate: CustomDelegate {}

View File

@ -109,6 +109,7 @@ private slots:
void emptyModel();
void updatedModifiedModel();
void insertRows();
void toggleExpandedUsingArrowKeys();
};
tst_qquicktreeview::tst_qquicktreeview()
@ -731,6 +732,68 @@ void tst_qquicktreeview::expandToIndex()
QCOMPARE(treeView->rows(), 13);
}
void tst_qquicktreeview::toggleExpandedUsingArrowKeys()
{
// Check that you can use the left and right arrow key to
// expand and collapse nodes in the tree.
LOAD_TREEVIEW("normaltreeview.qml");
treeView->setFocus(true);
QQuickWindow *window = treeView->window();
// Start by making cell 0, 0 current
treeView->selectionModel()->setCurrentIndex(treeView->modelIndex(0, 0), QItemSelectionModel::NoUpdate);
// Expand row 0
const int row0 = 0;
QCOMPARE(treeView->rows(), 1);
QVERIFY(!treeView->isExpanded(row0));
QTest::keyPress(window, Qt::Key_Right);
QVERIFY(treeView->isExpanded(row0));
// A polish event was scheduled, but since the call to keyPress() processes
// events, WAIT_UNTIL_POLISHED will be unreliable. So use QTRY_COMPARE instead.
QTRY_COMPARE(treeView->rows(), 5);
// Hitting Key_Right again should be a no-op
QTest::keyPress(window, Qt::Key_Right);
QVERIFY(treeView->isExpanded(row0));
QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->modelIndex(0, row0));
// Move down to row 1 and try to expand it. Since Row 1
// doesn't have children, expanding it will be a no-op.
// And also, it shouldn't move currentIndex to the next
// column either, it should stay in the tree column.
const int row1 = 1;
QVERIFY(!treeView->isExpanded(row1));
QTest::keyPress(window, Qt::Key_Down);
QTest::keyPress(window, Qt::Key_Right);
QVERIFY(!treeView->isExpanded(row1));
QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->modelIndex(0, row1));
// Move down to row 4 and expand it
const int row4 = 4;
QCOMPARE(treeView->rows(), 5);
while (treeView->currentRow() != row4)
QTest::keyPress(window, Qt::Key_Down);
QVERIFY(!treeView->isExpanded(row4));
QTest::keyPress(window, Qt::Key_Right);
QVERIFY(treeView->isExpanded(row4));
QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->modelIndex(0, row4));
// Move up again to row 0 and collapse it
while (treeView->currentRow() != row0)
QTest::keyPress(window, Qt::Key_Up);
QVERIFY(treeView->isExpanded(row0));
QTest::keyPress(window, Qt::Key_Left);
QVERIFY(!treeView->isExpanded(row0));
QTRY_COMPARE(treeView->rows(), 1);
// Hitting Key_Left again should be a no-op
QTest::keyPress(window, Qt::Key_Left);
QVERIFY(!treeView->isExpanded(row0));
QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->modelIndex(0, row0));
}
QTEST_MAIN(tst_qquicktreeview)