两次实例化 QStyledItemDelegate 的子类时出现“Python 已停止工作”错误

Posted

技术标签:

【中文标题】两次实例化 QStyledItemDelegate 的子类时出现“Python 已停止工作”错误【英文标题】:"Python has stopped working" error when instantiating subclass of QStyledItemDelegate twice 【发布时间】:2021-09-24 13:26:36 【问题描述】:

我有以下代码来对齐 QTableWidget 列的文本。

import sys

from PyQt5           import QtWidgets, QtCore
from PyQt5.QtCore    import Qt
from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, QStyledItemDelegate

class AlignRightDelegate(QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(AlignRightDelegate, self).initStyleOption(option, index)
        option.displayAlignment = Qt.AlignRight

class Table(QTableWidget):
    def __init__(self, data, alignColumns = 1, *args):
        QTableWidget.__init__(self, *args)
        self.setRowCount(len(data))
        self.setColumnCount(3)

        self.setData(data)
        self.resizeColumnsToContents()

        for colIndex in range(1, 1 + alignColumns):
            print("Align Column [", colIndex, "]", sep="")
            self.setItemDelegateForColumn(colIndex, AlignRightDelegate())

    def setData(self, data): 
        horizontalHeaders = []
        for m, rowContent in enumerate(data):
            for n, cellContent in enumerate(data[m]):
                if (m == 0):
                    horizontalHeaders.append(cellContent)
                else:
                    self.setItem(m - 1, n, QTableWidgetItem(cellContent))
        self.setHorizontalHeaderLabels(horizontalHeaders)

if __name__ == "__main__":
    data = [["col1", "col2", "col3"],
            [   "1",   "1", "a"],
            [  "-1",   "2", "b"], 
            [   "0",   "3", "c"]]
    print("python QTableWidgetAlignRight.py[ <AlignColumnCount=1]")
    app = QApplication(sys.argv)
    table = Table(data, int(sys.argv[1])) if (len(sys.argv) > 1) else Table(data)
    table.show()
    sys.exit(app.exec_())

如果我使用python QTableWidgetAlignRight.py 1 执行上面的代码,它有点工作,它应该如下所示,col2 与右侧对齐但显然与也顶

但是,当我使用 python QTableWidgetAlignRight.py 2 执行相同的代码时,我尝试将 2 列向右对齐,我遇到了 Python has stopped working error。以下截图其实是在我的日文Windows OS(Win 10 Pro 20H2 (OS Build 19402.1165))

但是我在网上搜索了相同的英文错误消息,我发现了一个屏幕截图,尽管不是由于我上面的代码(从这个页面挖掘:Python has stopped working)。

那么对齐我的 QTableWidget 的 2 列的正确方法是什么(没有错误并且没有垂直对齐到顶部)?这也是 PyQt5 中的一个错误吗?

为了您的信息,我正在使用以下内容:Python 3.7.6conda 4.8.2pyqt 5.9.2 py37h6538335_2。对于列对齐,我查看了这个以供参考:How to align all items in a column to center in QTableWidget

【问题讨论】:

【参考方案1】:

由于 python 和 PyQt 保持对对象的引用的方式,只有 one unparentedunreferenced 委托可以理论上为每个视图设置。

但是,虽然可以像这样设置一个委托,但不应该这样做:委托应该始终具有持久引用或有效的父级,因为视图没有 获得委托的所有权(请参阅所有 setItemDelegate* 函数的文档)。

另外,考虑到您对多个列使用相同的委托,创建多个列是没有意义的。

    self.alignDelegate = AlignRightDelegate(self)
    for colIndex in range(1, 1 + alignColumns):
        print("Align Column [", colIndex, "]", sep="")
        self.setItemDelegateForColumn(colIndex, self.alignDelegate)

请注意,您可以使用父参数 (self) 创建实例属性:

self.alignDelegate = AlignRightDelegate()
# or
alignDelegate = AlignRightDelegate(self)

不过,同时使用这两个不是问题,并且在处理 Qt 对象时指定父对象是一个不错的选择。 在任何情况下,至少应始终使用上述方法之一。

你得到一个错误的对齐方式,因为你只设置了水平对齐方式:使用option.displayAlignment = Qt.AlignRight | Qt.AlignVCenter

【讨论】:

第一段有错别字吗?就目前而言,这似乎是矛盾的。 @ekhumoro 也许我应该换个说法:我的意思是在 PyQt 中可以使用未引用的委托实例,但只有一个:只要它试图为相同的创建另一个查看,程序将冻结。因此,虽然它在技术上有效,但不应该这样做。 所以它应该是“一个”而不是“一个”。但是,我仍然认为建议应该始终保持参考 - 特别是当文档声明 Qt 不拥有所有权时。说它“可以”在 PyQt 中完成表明它在某种意义上得到了明确的支持,而不仅仅是一个实现细节。 @ekhumoro 好点,再次。我已经更新了答案,我相信现在应该更清楚了。

以上是关于两次实例化 QStyledItemDelegate 的子类时出现“Python 已停止工作”错误的主要内容,如果未能解决你的问题,请参考以下文章

QSpacerItem 在实例化两次时使 pyQT 崩溃

C++ boost线程在实例化两次时导致分段错误

Flask-Mail Mail()实例化两次

必须使用延迟实例化的UI视图将子视图添加到视图控制器两次

使用 QStyledItemDelegate::paint() 直接在 QListView 上绘制小部件

PyQt:在 QStyledItemDelegate 中使用 QTextEdit 作为编辑器