尝试覆盖 QTreeView.edit() 时出现最大递归错误

Getting Maximum Recursion Error when trying to override QTreeView.edit()

标题说明了大部分内容。我必须在这里做一些愚蠢的事情,但是出于某种原因,当我右键单击 Treeview 时,每当我尝试覆盖 QTreeView 的编辑功能时,我都会收到最大递归深度错误。

这是我尝试调用 super 的编辑功能时的具体情况。这是问题的示例。我在这里搞砸了什么?

from PyQt5 import QtWidgets, QtGui, QtCore


class EditTreeView(QtWidgets.QTreeView):

    editingRequested = QtCore.pyqtSignal(QtCore.QModelIndex)

    def __init__(self, parent=None):
        super(EditTreeView, self).__init__(parent)

    def edit(self, index, QAbstractItemView_EditTrigger=None, QEvent=None):
        super(EditTreeView, self).edit(index)


class testTreeview(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(testTreeview, self).__init__(parent)
        self.mainTree = EditTreeView()
        self.lo = QtWidgets.QVBoxLayout()
        self.lo.addWidget(self.mainTree)
        self.setLayout(self.lo)
        self.model = QtGui.QStandardItemModel()
        self.mainTree.setModel(self.model)

    def populate(self):
        row = [QtGui.QStandardItem('teststuff'), ]
        root = self.model.invisibleRootItem()
        root.appendRow(row)


if __name__ == "__main__":
    from PyQt5 import QtCore, QtGui, QtWidgets

    app = QtWidgets.QApplication([])
    volume = testTreeview()
    volume.show()
    app.exec_()

解释:

QTreeView 继承自 QAbstractItemView,如果您查看 class 的方法,您会发现有 2 个同名方法:

bool QAbstractItemView::edit(const QModelIndex &index, QAbstractItemView::EditTrigger trigger, QEvent *event)

Starts editing the item at index, creating an editor if necessary, and returns true if the view's State is now EditingState; otherwise returns false.

The action that caused the editing process is described by trigger, and the associated event is specified by event.

Editing can be forced by specifying the trigger to be QAbstractItemView::AllEditTriggers.


void QAbstractItemView::edit(const QModelIndex &index)

Starts editing the item corresponding to the given index if it is editable.

Note that this function does not change the current index. Since the current index defines the next and previous items to edit, users may find that keyboard navigation does not work as expected. To provide consistent navigation behavior, call setCurrentIndex() before this function with the same model index.

观察到第一种方法比第二种方法更通用,所以它让我们怀疑第二种方法会使用第一种方法,如果 the source code 审查确实会发生这种情况:

void QAbstractItemView::edit(const QModelIndex & index)
{
    Q_D(QAbstractItemView);
    if (Q_UNLIKELY(!d->isIndexIsValid(index)))
        qWarning("edit: index was invalid");
    if (Q_UNLIKELY(!<b>edit(index, AllEditTriggers, 0)</b>))
        qWarning("edit: editing failed");
}</pre>

所以你的情况把错误解释清楚:你是重写了第一个方法调用了第二个,但是第二个按照源码使用了第一个,又回到了死循环。


解决方案

解决方案是使用所有参数的相同方法的super:

class EditTreeView(QtWidgets.QTreeView):
    editingRequested = QtCore.pyqtSignal(QtCore.QModelIndex)

    def edit(self, index, trigger, event):
        self.editingRequested.emit(index)
        return super(EditTreeView, self).edit(index, trigger, event)

但请记住,重写是关于第一个方法的,在 C++ 中,允许具有相同名称的方法,但在 python 中,如果有多个方法具有相同的名称,则最后一个将删除之前的。