当 QtItemDelegate 子类有两个或更多实例时,PyQt 崩溃

问题描述 投票:0回答:1

我正在为 QTableView 实现一个委托,其中两列应该是下拉列表,用户可以从枚举中选择一个值。

下面是一个例子:

from PyQt4 import QtGui, QtCore
import enum

Color = enum.Enum("Color", ("RED", "BLUE"))
Shape = enum.Enum("Shape", ("TRIANGLE", "CIRCLE"))


class EnumComboBoxDelegate(QtGui.QItemDelegate):
    def __init__(self, enum_cls, parent=None):
        super(EnumComboBoxDelegate, self).__init__(parent)
        self.enum_cls = enum_cls
        self.enum_objects = list(enum_cls)
        self.enum_names = [enum_obj.name for enum_obj in self.enum_objects]
        self.enum_values = [enum_obj.value for enum_obj in self.enum_objects]

    def createEditor(self, widget, option, index):
        editor = QtGui.QComboBox(widget)
        for user_friendly_name in self.enum_names:
            editor.addItem(user_friendly_name)
        return editor

    def setEditorData(self, editor, index):
        combobox_index, is_int = index.model().data(index, QtCore.Qt.EditRole).toInt()
        if is_int:
            editor.setCurrentIndex(combobox_index)
        else:
            editor.setCurrentIndex(0)

    def setModelData(self, editor, model, index):
        combobox_index = editor.currentIndex()
        if not combobox_index:
            combobox_index = 0

        model.setData(index, combobox_index, QtCore.Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


class CentralWidget(QtGui.QWidget):
    def __init__(self, *args, **kwargs):
        super(CentralWidget, self).__init__(*args, **kwargs)

        main_layout = QtGui.QVBoxLayout()

        table_view = QtGui.QTableView()
        table_view.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        table_view.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)

        table_model = QtGui.QStandardItemModel(2, 2, None)
        table_view.setModel(table_model)

        color_combo_delegate = EnumComboBoxDelegate(Color)
        table_view.setItemDelegateForColumn(0, color_combo_delegate)

        shape_combo_delegate = EnumComboBoxDelegate(Shape)
        table_view.setItemDelegateForColumn(1, shape_combo_delegate)

        main_layout.addWidget(table_view)

        self.setLayout(main_layout)


def run_self_contained_widget():
    import sys

    app = QtGui.QApplication(sys.argv)
    main_window = QtGui.QMainWindow()
    main_window.setCentralWidget(CentralWidget())
    main_window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    run_self_contained_widget()

现在,如果运行,代码会在启动时崩溃而没有回溯:

Process finished with exit code -1073741819 (0xC0000005)

如果我更改委托,使它们都使用相同的

EnumComboBoxDelegate
实例,我不会收到任何错误:

color_combo_delegate = EnumComboBoxDelegate(Color)
table_view.setItemDelegateForColumn(0, color_combo_delegate)

shape_combo_delegate = EnumComboBoxDelegate(Shape)
table_view.setItemDelegateForColumn(1, color_combo_delegate)

造成这种情况的原因是什么以及如何解决?该代码使用 PyQt4 和 Python 2.7,但在 Python 3.x 中似乎是相同的

python qt pyqt lifetime qitemdelegate
1个回答
0
投票

我可以提供部分解决方案,但我还没有弄清楚到底为什么。看起来 color_combo_delegate 在

CentralWidget.__init__()
结束时被垃圾收集。如果将以下内容添加到
EnumComboBoxDelegate

    def __del__(self):
        print("Oh no! I am about to be destroyed! Enum: {}".format(self.enum_cls.__name__))

你得到输出

Oh no! I am about to be destroyed! Enum: Color
Process finished with exit code -1073741819 (0xC0000005)

固定代码为:

self.color_combo_delegate = EnumComboBoxDelegate(Color)
table_view.setItemDelegateForColumn(0, self.color_combo_delegate)

self.shape_combo_delegate = EnumComboBoxDelegate(Shape)
table_view.setItemDelegateForColumn(1, self.shape_combo_delegate)

我不清楚为什么存在对 shape_combo_delegate 的引用,而不存在对 color_combo_delegate 的引用,但这似乎解决了问题。

© www.soinside.com 2019 - 2024. All rights reserved.