PyQt5 如何在 QTableWidget 上按回车键并转到下面的单元格?

PyQt5 How to press enter on a QTableWidget and go to the cell below?

我正在尝试使用 PyQt5 和 Python.

来制作一个像 excel 表格一样的 QTableWidget

为此,我想激活按下回车键的选项,下面的单元格将成为焦点。

如何操作?

这是我的尝试:

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        row = self.tableWidget.currentRow()
        col = self.tableWidget.currentColumn()
        if event.key() == Qt.Key_Enter and row < self.tableWidget.rowCount():
            row += 1
            self.tableWidget.setCurrentCell(row, col)
            self.tableWidget.edit(self.tableWidget.currentIndex())

我在 PySide2 中做了一段时间,但它应该大部分相同。

首先扩展QTableWidget:

class FooTable(QTableWidget):
    def __init__(self):
        super().__init__()

然后将以下内容作为方法实现:

def keyPressEvent(self, event: QtGui.QKeyEvent):
    if event.key() == Qt.Key_Return:  # 16777220 # Enter
        col = self.currentColumn()
        row = self.currentRow()
        self.setCurrentCell(row + 1, col)

祝你好运。

您的尝试没有成功,因为您想要响应的 keyPressEvent 必须由 table 接收,这不是您的情况,因为您显然正在尝试这样做来自包含 table.

的父 window

当按键事件发生时,当前 focused 小部件接收它;如果该小部件对该事件不感兴趣,它将被发送回该小部件的父级,依此类推,直到某个小部件实际上能够对该事件做出反应并且可能接受它;一旦事件被接受,父控件将不会收到它。

虽然一些小部件只是忽略一些或任何键盘事件(例如,QLabel),但其他小部件只是“吃掉”几乎所有事件,这就是像 QTableWidget 这样的项目视图的情况。如果 table 有焦点,当它收到 return 键事件时它将接受它,该事件将不再传播,这就是为什么你无法从你的 keyPressEvent 覆盖。

最常用的解决方案是子class table 并为 class 实施 keyPressEvent(如 中所述)。

一个常见的替代方法是使用事件过滤器,如果您使用的是在 Designer 中创建的 GUI,这将非常有用,因为它允许添加小功能而无需 subclass 和使用提升小部件。

class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.tableWidget = QtWidgets.QTableWidget
        self.setCentralWidget(self.tableWidget)
        self.tableWidget.installEventFilter(self)

    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.KeyPress and 
            event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter)):
                # ensure that the table receives the key event first
                res = super().eventFilter(source, event)
                current = self.tableWidget.currentIndex()
                nextIndex = current.sibling(current.row() + 1, current.column())
                if nextIndex.isValid():
                    self.tableWidget.setCurrentIndex(nextIndex)
                    self.tableWidget.edit(nextIndex)
                return res
        return super().eventFilter(source, event)

最后,还有“猴子补丁”,只要需要非常简单的 class 修改就可以使用它,而无需创建子 classes。这也适用于设计器创建的 GUI。
请注意,猴子修补不适用于 一切 :某些方法无法被覆盖,尤其是在实例被覆盖后;值得注意的是,PyQt 使用缓存函数绑定,这意味着如果在覆盖它之前调用了基本实现方法,则之后无法覆盖它。

class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.tableWidget = QtWidgets.QTableWidget
        self.setCentralWidget(self.tableWidget)
        self.tableWidget.keyPressEvent = self.tableKeyPressEvent

    def tableKeyPressEvent(self, event):
        # call the base implementation, do *not* use super()!
        QtWidgets.QTableWidget.keyPressEvent(self.tableWidget, event)
        if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
            current = self.tableWidget.currentIndex()
            nextIndex = current.sibling(current.row() + 1, current.column())
            if nextIndex.isValid():
                self.tableWidget.setCurrentIndex(nextIndex)
                self.tableWidget.edit(nextIndex)