سؤال

I want to make grid of 8 buttons (2x4) and be able to move through this buttons using keyboard arrows. If I simply make a grid layout and put the pushbuttons in corresponding coordinates, i get the layout that looks as it should but I can only move left and right and when i come to the end of first row then the focus jumps to the first button in second row (i.e. UP button doesn't move focus down, instead it does same as button RIGHT). I noticed that the way that focus (cursor) moves through buttons isn't connected to their place in grid, but to order I created them in code.

How to override this behavior and allow user to move through grid of buttons?

هل كانت مفيدة؟

المحلول

You can install an event filter for every button and catch key presses there.

This is an example of how you can implement such navigation:

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    grid = new QGridLayout;

    for (int row = 0; row < 4; ++row)
    {
        for (int col = 0; col < 4; ++col)
        {
            QString text = QString("btn %1/%2").arg(row).arg(col);
            QPushButton *btn = new QPushButton(text);
            btn->installEventFilter(this);

            grid->addWidget(btn, row, col);
        }
    }

    setLayout(grid);
}

bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    QPushButton *btn = dynamic_cast<QPushButton*>(obj);
    if (btn != NULL && event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);

        int index = grid->indexOf(btn);
        int row, col, rowSpan, colSpan;
        grid->getItemPosition(index, &row, &col, &rowSpan, &colSpan);

        int nextRow = row;
        int nextCol = col;

        bool keyArrow = true;
        int key = keyEvent->key();
        switch (key)
        {
        case Qt::Key_Up:
        {
            nextRow--;
            if (nextRow < 0)
            {
                nextRow = grid->rowCount() - 1;
            }
            break;
        }
        case Qt::Key_Down:
        {
            nextRow++;
            if (nextRow >= grid->rowCount())
            {
                nextRow = 0;
            }
            break;
        }
        case Qt::Key_Right:
        {
            nextCol++;
            if (nextCol >= grid->columnCount())
            {
                nextCol = 0;
            }
            break;
        }
        case Qt::Key_Left:
        {
            nextCol--;
            if (nextCol < 0)
            {
                nextCol = grid->columnCount() - 1;
            }
            break;
        }
        default:
        {
            keyArrow = false;
        }
        }

        if (keyArrow)
        {
            grid->itemAtPosition(nextRow, nextCol)->widget()->setFocus();
        }

        return true;

    }

    return QWidget::eventFilter(obj, event);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top