我自定义了一个对话框,当按下Tab键时,焦点从按钮切换到表格小部件。我希望在遍历表格小部件中的所有项目后,焦点返回到初始按钮。这是一个最小的可重现示例:
#include <QApplication>
#include <QPushButton>
#include <QTableWidget>
#include <QVBoxLayout>
class Widget : public QWidget
{
public:
explicit Widget()
{
setLayout(&vl);
tw.setRowCount(1);
tw.setColumnCount(3);
vl.addWidget(&btn);
vl.addWidget(&tw);
}
bool focusNextPrevChild(bool next)
{
QWidget* focusWidget = this->focusWidget();
if (focusWidget == &tw)
{
int currentRow = tw.currentRow();
int currentCol = tw.currentColumn();
int lastRow = tw.rowCount() - 1;
int lastCol = tw.columnCount() - 1;
if (next && currentRow == lastRow && currentCol == lastCol)
{
tw.clearFocus();
return true;
}
}
return QWidget::focusNextPrevChild(next);
}
private:
QPushButton btn;
QTableWidget tw;
QVBoxLayout vl;
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
我尝试覆盖
focusNextPrevChild
函数,但它不起作用。一旦焦点进入表格小部件,就无法离开它。
您正在覆盖父级的
,这是完全没有意义的,因为只要表格小部件管理它,它就永远不会被触发。 [...]focusNextPrevChild
您可以通过添加
qDebug
来检查 focusWidget
中的 focusNextPrevChild
来进行检查。 if (focusWidget == &tw)
检查永远不会是 true
。
实施。moveCursor()
moveCursor()
来实现你想要的:
#include <QApplication>
#include <QPushButton>
#include <QTableWidget>
#include <QVBoxLayout>
#include <QKeyEvent>
class TableWidget : public QTableWidget
{
Q_OBJECT
signals:
void firstItemBackTab();
void lastItemTab();
protected:
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
{
QModelIndex current = currentIndex();
int row = current.row();
int col = current.column();
int lastRow = rowCount() - 1;
int lastCol = columnCount() - 1;
//tab press on the last cell
if(cursorAction == MoveNext && row == lastRow && col == lastCol)
emit lastItemTab();
//tab+shift (backtab) press on the first cell
if(cursorAction == MovePrevious && row == 0 && col == 0)
emit firstItemBackTab();
return QTableWidget::moveCursor(cursorAction, modifiers);
}
void focusInEvent(QFocusEvent *event) override
{
QTableWidget::focusInEvent(event);
if(hasFocus())
{
//if the tab navigation is going forward,
//as a user, I'd expect the first cell to be active
if(event->reason() == Qt::TabFocusReason)
{
setCurrentCell(0, 0);
}
//if the tab navigation is going backwards,
//as a user, I'd expect the last cell to be active
else if(event->reason() == Qt::BacktabFocusReason)
{
setCurrentCell(rowCount() - 1, columnCount() - 1);
}
}
}
};
class Widget : public QWidget
{
public:
explicit Widget()
{
setLayout(&vl);
tw.setRowCount(3);
tw.setColumnCount(3);
vl.addWidget(&btn);
vl.addWidget(&tw);
vl.addWidget(&btn1);
//the weakest point of this approach is here (as far as my "expertise" go)
//it's possible the next/previous child is not what you'd expect.
//Tab order and all. Perhaps QWidget::setTabOrder could help with that.
connect(&tw, &TableWidget::firstItemBackTab, [=]()
{
focusPreviousChild();
});
connect(&tw, &TableWidget::lastItemTab, [=]()
{
focusNextChild();
});
}
private:
QPushButton btn{"Button 1"};
TableWidget tw;
QPushButton btn1{"Button 2"};
QVBoxLayout vl;
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"
moveCursor
此处替换了focusNextPrevChild
中的逻辑,并使用已经可用的QAbstractItemView::CursorAction
替换了对下一个/上一个的检查。
此方法适用于基本的小部件单元。所以,我认为没有理由重新实现
focusNextPrevChild
。当您的单元格小部件很复杂并且您想要自定义其中的选项卡导航顺序时,您可能会希望这样做。但根据您在focusNextPrevChild
中实现的逻辑,基本方法应该足够了。
演示: