You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mac OS Monterey 12.4运行PyQt5触发zsh segmentation fault报错

问题根因

触发zsh: segmentation fault段错误的核心是三个逻辑错误:

  • 每次itemChanged信号触发时都重复新建Delegate对象并重新绑定给表格。Qt替换委托时会销毁旧实例,如果旧实例正处于绘制流程中,就会触发野指针内存访问,直接在MacOS上触发段错误。委托属于表格静态配置,不需要在单元格内容变化时重复创建绑定。
  • itemChanged信号并非仅在用户手动修改单元格时触发:插入新行、程序修改单元格内容、委托重绘触发的数据刷新都会触发该信号,导致反复创建委托的逻辑被递归调用,进一步放大内存访问问题。
  • 委托实现不规范:IntDelegate初始化时没有将parent参数传入父类,FloatDelegate混用QItemDelegate和QStyledItemDelegate类型,paint方法没有处理单元格选中、焦点等默认状态,空单元格取值时缺少兼容逻辑,也会加剧异常概率。
修复方案
  • 把委托的初始化、绑定逻辑移到表格初始化阶段,全局只执行一次,禁止在itemChanged槽函数中重复创建、绑定委托。
  • 所有会修改表格结构、内容的逻辑,执行前先阻塞itemChanged信号,避免操作过程中递归触发槽函数。
  • 统一委托父类为QStyledItemDelegate,修正paint逻辑:先绘制单元格默认的背景、选中、焦点状态,再绘制居中的文本内容,补全空值判断避免类型转换异常。
  • 如果仅需要实现文本居中对齐,不需要自定义委托,直接调用QTableWidgetItem.setTextAlignment(Qt.AlignCenter)即可,逻辑更简单也不会出现生命周期问题。
修正后核心代码

表格初始化逻辑调整

将委托绑定移到初始化函数中,仅执行一次:

def impostazione_data_mapper(self):
    font = QtGui.QFont()
    font.setBold(True)
    self.tW_GrossMargin.setColumnCount(7)
    self.tW_GrossMargin.setRowCount(10)
    self.tW_GrossMargin.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
    
    intestazioni=[]
    intestazioni.append("Range - quantità da")
    intestazioni.append("Range - quantità a")
    intestazioni.append("Vendita - Gross margin Italia")
    intestazioni.append("Vendita - Gross margin Estero")
    intestazioni.append("Conto lavorazione - Gross margin Italia")
    intestazioni.append("Conto lavorazione - Gross margin Estero")
    intestazioni.append(" ")
    self.tW_GrossMargin.setHorizontalHeaderLabels(intestazioni)
    
    self.tW_GrossMargin.resizeColumnsToContents()
    header = self.tW_GrossMargin.horizontalHeader()
    header.setDefaultAlignment(Qt.AlignCenter|Qt.AlignVCenter)
    self.tW_GrossMargin.resizeColumnsToContents()

    for c in range(self.tW_GrossMargin.columnCount() - 1):
        h_item = self.tW_GrossMargin.horizontalHeaderItem(c)
        h_item.setFont(font)

    self.tW_GrossMargin.resizeColumnsToContents()

    # 委托仅初始化、绑定一次
    self.int_delegate = IntDelegate(self.tW_GrossMargin)
    self.float_delegate = FloatDelegate(3, self.tW_GrossMargin)
    self.tW_GrossMargin.setItemDelegateForColumn(0, self.int_delegate)
    self.tW_GrossMargin.setItemDelegateForColumn(1, self.int_delegate)
    for col in range(2, 7):
        self.tW_GrossMargin.setItemDelegateForColumn(col, self.float_delegate)

槽函数逻辑调整

去掉槽函数里重复设置委托的代码,增加信号阻塞避免递归触发:

def allinea_campi(self, item):
    self.tW_GrossMargin.blockSignals(True)
    try:
        # 此处仅保留数据校验、内容调整类逻辑,不要重复绑定委托
        row = item.row()
        col = item.column()
        # 如果仅需要居中对齐,直接用下面这行即可,不需要自定义委托
        # item.setTextAlignment(Qt.AlignCenter)
    finally:
        self.tW_GrossMargin.blockSignals(False)

def nuovo_margine(self):  
    self.tW_GrossMargin.blockSignals(True)
    try:
        numRows = self.tW_GrossMargin.rowCount()
        self.tW_GrossMargin.insertRow(numRows)
    finally:
        self.tW_GrossMargin.blockSignals(False)

委托类实现修正

class IntDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        # 必须传入parent,由Qt管理对象生命周期
        super().__init__(parent)
   
    def paint(self, painter, option, index):    
        # 先绘制单元格默认的背景、选中、焦点状态
        self.initStyleOption(option, index)
        option.text = ""
        style = option.widget.style() if option.widget else QApplication.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, painter, option.widget)
        
        value = index.model().data(index, Qt.EditRole)
        if value in (None, ""):
            return
        painter.drawText(option.rect, Qt.AlignCenter, str(value))
              
class FloatDelegate(QStyledItemDelegate):
    def __init__(self, decimals, parent=None):
        # 统一使用QStyledItemDelegate作为父类
        super().__init__(parent)
        self.nDecimals = decimals

    def paint(self, painter, option, index):
        # 先绘制默认单元格状态
        self.initStyleOption(option, index)
        option.text = ""
        style = option.widget.style() if option.widget else QApplication.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, painter, option.widget)
        
        value = index.model().data(index, Qt.EditRole)
        try:
            if value in (None, ""):
                return
            number = float(value)
            painter.drawText(option.rect, Qt.AlignCenter | Qt.AlignVCenter, f"{number:.{self.nDecimals}f}")
        except:
            super().paint(painter, option, index)

内容的提问来源于stack exchange,提问作者MDR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:57:18