Using tab and backtab to shift between first and last item within a GridView in QML

42 views Asked by At

I know this is completely wrong but I have tried a few things (still a beginner). I have successfully managed to set up a GridView that has 16 items in it. I can navigate through the items successfully using the arrow keys and select using the return key. I now want to use the tab key to go to the first item (i.e. the top left item in the grid view) and use the back tab key to go to the last item (i.e. the bottom right item in the grid view).

This is what I have got so far (note that I have defined these items on a separate QML page (the up,down,left and right all work but the topLeft and bottomRight don't):

    property Item leftItem
    property Item rightItem
    property Item topItem
    property Item bottomItem
    property Item topLeft
    property Item bottomRight 

This is the main bit of the code for key navigation in main.qml:

GridView {
            id: gridView
            width: 800
            height: 800
            cellWidth: 200
            cellHeight: 200
            model: cardsModel 
            interactive: true
            focus: true  focus
            delegate: CustomRectangle {
                filePath: filePath1
                leftItem: index % 4 === 0 ? null : gridView.itemAt(index - 1)
                rightItem: (index + 1) % 4 === 0 ? null : gridView.itemAt(index + 1)
                topItem: index < 4 ? null : gridView.itemAt(index - 4)
                bottomItem: index > 11 ? null : gridView.itemAt(index + 4)
                topLeft: gridView.itemAt(0) 
                bottomRight: gridView.itemAt(gridView.count-1)

                    Keys.onPressed: {
                        if (event.key === Qt.Key_Left && leftItem) {
                            leftItem.forceActiveFocus()
                            focus = true
                        } else if (event.key === Qt.Key_Right && rightItem) {
                            rightItem.forceActiveFocus()
                            focus = true
                        } else if (event.key === Qt.Key_Up && topItem) {
                            topItem.forceActiveFocus()
                            focus = true
                        } else if (event.key === Qt.Key_Down && bottomItem) {
                            bottomItem.forceActiveFocus()
                            focus = true
                        } else if (event.key === Qt.Key_Tab) {
                            gridView.itemAt(0).forceActiveFocus()
                            focus = true
                            } else if (event.key === Qt.Key_Backtab) {
                            gridView.itemAt(gridView.count - 1).forceActiveFocus()
                            focus = true
                            } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
                                flipCard()
                                flipped = true
                                focus = true
                                cardClicked()
                            }
                        }

The tab and backtab key lines raise an error that says insufficient arguments.

Please help! Thank you in advance! :)

1

There are 1 answers

0
Stephen Quan On

You would save a lot of trouble if your delegate is set to a Button. You can hide the fact that it is a Button by styling it appropriately. As a Button you would inherit all key navigations such as arrow keys, tab, and back tab.

    GridView {
        model: 16
        width: 800
        height: 800
        cellWidth: 200
        cellHeight: 200
        delegate: Button {
            id: btn
            width: 200
            height: 200
            onFocusChanged: if (focus) GridView.view.currentIndex = index;
            background: Rectangle {
                color: btn.pressed && "orange"
                    || btn.focus && "lightcyan" 
                    || "transparent"
                border.color: "#40808080"
            }
        }
        highlight: Rectangle {
            border.color: "red"
            border.width: 2
            color: "transparent"
            z: 2
        }
    }

You can Try it Online!