使用QT中的箭头在小部件之间导航

3
我正在使用QT开发UI界面。这个界面很简单,像iPhone或Android应用一样。假设有9个项目(3行x 3列)。
我想要做的是使用箭头键在小部件之间进行导航。 如果焦点在[第1行,第1列],并且我按下向下箭头,我希望它到达[第2行,第1列]。 另一个例子是,如果焦点在[第2行,第3列],并且我按下向上箭头,我希望它到达[第1行,第3列]。
但当前的行为是向上和向右总是转到下一个小部件,而向下和向左总是转到上一个小部件。
在QT中是否有实现这个功能的方法?还是我需要创建一些算法来实现?
谢谢

所有9个项目同时可见吗? - Maxim Makhun
安装一个带有开关的事件处理程序,并根据按下的键设置所需的焦点。 - Thomas Ayoub
@Samoth:当然,但是如果能提供一些代码以获取更多细节会更有用,即使是伪代码也可以。 - László Papp
2个回答

3

更新:请查看最后的惊人示例。

基本的小部件焦点导航从这里开始:

http://qt-project.org/doc/qt-4.8/focus.html

箭头导航可以很容易地使用 QTableView 来实现:

http://qt-project.org/doc/qt-4.8/qtableview.html#navigation

如果您可以让您的小部件在 QTableView 的结构内工作,则不需要实现此功能,它作为包装器/视图小部件的一部分而存在。

http://qt-project.org/doc/qt-4.8/qtablewidget.html#details

http://qt-project.org/doc/qt-4.8/model-view-programming.html

模型视图编程确实有一个学习曲线,但值得学习和使用。

但这绝不是实现此目标的唯一方法。

可以利用事件过滤器、键事件、焦点事件来完成此功能,而不使用 QTableView QTableWidget 。 但是,找到最佳方法而不使其看起来凌乱可能需要一些时间。

http://qt-project.org/doc/qt-4.8/qcoreapplication.html#notify

http://doc.qt.digia.com/qq/qq11-events.html

http://qt-project.org/doc/qt-4.8/eventsandfilters.html

http://qt-project.org/doc/qt-4.8/qkeyevent.html#details

http://qt-project.org/doc/qt-4.8/qfocusevent.html

键事件设置为具有焦点的项目,如果它们忽略事件,则向上传播到其父项。 因此,只要您表格/网格中的项目忽略与箭头键有关的键事件,那么您的父部件就可以监听键事件并适当处理它们。

http://qt-project.org/doc/qt-4.8/qt.html#Key-enum

http://qt-project.org/doc/qt-4.8/qt.html#FocusReason-enum

http://qt-project.org/doc/qt-4.8/qwidget.html#setFocus

http://qt-project.org/doc/qt-4.8/qapplication.html#focusWidget

希望能帮到您。

编辑:以下是一个完整的在QGraphicsView中实现你想要做的事情的示例:

Qt Creator > Welcome tab > Examples > Pad Navigator Example

http://qt-project.org/doc/qt-4.8/graphicsview-padnavigator.html

以下是示例中的相关代码:

// Enable key navigation using state transitions
for (int y = 0; y < rows; ++y) {
    for (int x = 0; x < columns; ++x) {
        QState *state = stateGrid[y][x];
        QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                       Qt::Key_Right, state);
        QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                      Qt::Key_Left, state);
        QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                      Qt::Key_Down, state);
        QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                    Qt::Key_Up, state);
        rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
        leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
        downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
        upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);

编辑: 使用QShortcutQGridLayout和一堆QPushButton的惊人示例:

widget.cpp

#include "widget.h"
#include <QPushButton>
#include <QApplication>
#include <QShortcut>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_grid = new QGridLayout;
    for(int r = 0; r < 10; r++)
    {
        for(int c = 0; c < 10; c++)
        {
            m_grid->addWidget(new QPushButton("Row " + QString::number(r)
                                              + ", Col " + QString::number(c)),
                              r, c);
        }
    }
    this->setLayout(m_grid);

    m_grid->itemAtPosition(1, 1)->widget()->setFocus();

    this->setStyleSheet("QPushButton::focus{ background: black; color: white;}");

    // only works for in Qt for Embedded Linux, Symbian and Windows CE only.
    //    QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional);

    QShortcut * shortcut;
    shortcut = new QShortcut(QKeySequence(Qt::Key_Up),this,
                             SLOT(on_up()));
    shortcut = new QShortcut(QKeySequence(Qt::Key_Down),this,
                             SLOT(on_down()));
    shortcut = new QShortcut(QKeySequence(Qt::Key_Left),this,
                             SLOT(on_left()));
    shortcut = new QShortcut(QKeySequence(Qt::Key_Right),this,
                             SLOT(on_right()));
}

void Widget::on_up()
{
    moveFocus(0, -1);
}

void Widget::on_down()
{
    moveFocus(0, 1);
}

void Widget::on_left()
{
    moveFocus(-1, 0);
}

void Widget::on_right()
{
    moveFocus(1, 0);
}

void Widget::moveFocus(int dx, int dy)
{
    if(qApp->focusWidget() == 0)
        return;
    int idx = m_grid->indexOf(qApp->focusWidget());
    if(idx == -1)
        return;
    int r, c, rowSpan, colSpan;
    m_grid->getItemPosition(idx, &r, &c, &rowSpan, &colSpan);
    QLayoutItem* layoutItem = m_grid->itemAtPosition(r + dy, c + dx);
    if(layoutItem == 0)
        return;
    layoutItem->widget()->setFocus();
}

Widget::~Widget()
{

}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGridLayout>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
    QGridLayout * m_grid;
public slots:
    void on_up();
    void on_down();
    void on_left();
    void on_right();
    void moveFocus(int dx, int dy);
};

#endif // WIDGET_H

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

2
哇,超过一半的帖子都是链接。最好实际给出一些内联解决方案,即使只是伪代码,而不是跳来跳去的链接。 - László Papp
你认为 @LaszloPapp 呢?有点进步了吗? :-) - phyatt

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接