如何正确捕获和过滤 QTableWidget 中的所有键盘事件?

How to properly catch and filter all keyboard events in a QTableWidget?

我想过滤 QWidgetTable 单元格中输入的字符,使其只接受十六进制字符(即过滤不代表十六进制值的 ascii 字符)。

我尝试了不同的选项,但仍然无法做到。

其中一个选项是实现我自己的小部件,使用我自己的 keyPressEvent 对 QWidgetTable 进行超类化,如下所示:

class MyQTableWidget(QTableWidget):

    def keyPressEvent(self, event):
        print("Item - Key pressed", event.key())
        super().keyPressEvent(event)
        #event.accept()

在这种情况下,事件处理程序仅捕获输入的第一个字符和最后一个“输入”键...如何捕获我在单元格中输入的所有字符?

我知道与小部件关联的编辑器可能是捕获所有中间键事件的编辑器,因此我尝试使用带有 eventFilfer() 的 QItemDelegate。 在这种情况下,我能够捕获所有关键事件,但这会破坏小部件的默认行为 ...

那么如何进行呢?

谢谢

您不能通过处理视图上的键事件来做到这一点。你只得到第一个键的原因是视图根据按下的键决定做什么:例如,如果你按下 navigation 键(箭头, tab, page, etc), 然后它会改变当前的项目。

如果 editTriggers() 包含 AnyKeyPressed(并且当前项目是可编辑的),则它进入编辑模式,为该索引创建一个编辑器,并将该键事件发送到编辑器。

也不鼓励在委托事件过滤器中处理事件,因为您可能会过滤掉不应过滤的事件,或者您可能会在使用剪贴板时接受无效输入。在你的情况下,如果你不小心,Ctrl+V 将无法访问,但如果你可以粘贴与十六进制语法不匹配的内容。

正确的解决方案是在编辑器上安装 QValidator,在这种情况下,您可以使用简单的 QRegExpValidator.

class HexDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        editor = super().createEditor(parent, opt, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            regexp = QtCore.QRegExp('[A-Fa-f0-9]+')
            validator = QtGui.QRegExpValidator(regexp)
            editor.setValidator(validator)
        return editor

app = QtWidgets.QApplication([])
table = QtWidgets.QTableWidget(10, 10)
table.setItemDelegate(HexDelegate(table))
table.show()
app.exec()

请注意,对于上面的正则表达式,+ 意味着 至少 必须输入一个字符才能接受 input:如果字段为空,你回车,编辑器不会提交这个值。如果要接受空值,请使用 [A-Fa-f0-9]*.

如果您需要特定数量的字符,请使用 {} 语法:

  • 接受 2 个字符:[A-Fa-f0-9]{2};
  • 接受至少2个字符:[A-Fa-f0-9]{2,};
  • 接受至少 2 个字符,但不超过 5 个:[A-Fa-f0-9]{2,5};

或者,当输入具有定义的最大长度时,您可以使用行编辑 inputMask:

class HexDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        editor = super().createEditor(parent, opt, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            editor.setInputMask('HHHHH;_')
        return editor

以上将需要正好 5 个十六进制字符,但您也可以 要求 至少 2 个字符(但不超过 5 个),使用 HHhhh;_。请注意,输入掩码不能接受未定义数量的字符,因此在这种情况下,您应该选择上面的验证器解决方案。