为 keyPressEvent 子类化 QTextEdit 是唯一的方法吗?

Is subclassing QTextEdit for keyPressEvent override the only way?

我正在使用 PySide2 构建一个 Qt 应用程序,它至少有一个类似于文本编辑器的视图。我有两个原因想要修改 QTextEdit 的 keyPressEvent 方法的功能:

  1. 添加使用用户定义的键盘操作来操作文本的功能(例如使用 tab/shift+tab 的标准 indent/dedent,尽管还有许多其他操作)。
  2. 为了促进某些未来的功能,正在显示的文本将存储在一个完全不同的结构中(不是 HTML/RTF/etc,而是一棵树)。这让我相信我不能将 QTextEdit 用作组合视图+控制器,而是必须提取控制器逻辑以在每次按键后正确修改底层结构,并将生成的文本提供给 QTextEdit。 (虽然,我已经考虑过利用 QTextEdit 在引擎盖下使用 HTML 的事实,可能使用 diva 标签隐藏结构。 请注意下面)

考虑到 Python 被解释,这两者的结合 - 加上希望也使用 QSyntaxHighlighter - 让我担心。如果每次按键都会执行大量的业务逻辑,那么它最终可能会非常引人注目。现在,我不想过早地进行优化,但我想避免走上一条看起来我可能不得不进行更耗时的更改的道路。我很好奇,如果没有用 C++ 编写 QTextEdit 子类,是否还有其他一些我没有想到的方法可能会更高效。

或者,如果似乎需要 QTextEdit 的 C++ 子类,则覆盖 keyPressEvent 是最好的方法。

请注意,以下更新与将业务登录注入 QTextEdit 的输入处理(并划分 view/controller 职责)的愿望没有直接关系,而是向其他任何人提供信息与项目 2 有类似的用例: 刚刚在 QtDesigner 中试用了小部件,<a> 锚点和 <meta> 标签都不能至少达到 "tag" 结构元素,同时对用户也是不可见的。 (<a name="something"></a> 不随文本移动,<meta> 始终移动到头部)。

您可以使用事件过滤器来处理按键,而无需子类化 QTextEdit

from PySide import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.edit = QtGui.QTextEdit(self)
        self.edit.installEventFilter(self)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.edit)

    def eventFilter(self, widget, event):
        if (event.type() == QtCore.QEvent.KeyPress and
            widget is self.edit):
            key = event.key()
            if key == QtCore.Qt.Key_Escape:
                print('escape')
            else:
                if key == QtCore.Qt.Key_Return:
                    self.edit.setText('return')
                elif key == QtCore.Qt.Key_Enter:
                    self.edit.setText('enter')
                return True
        return QtGui.QWidget.eventFilter(self, widget, event)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())