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

PyQt5中QTableView行下移触发Segmentation Fault,上移正常求解决

PyQt5 QTableView行下移崩溃问题解决

问题描述

基于PyQt5开发的GUI中,使用QTableView展示事件列表,上移行功能正常,但下移行时触发Segmentation Fault错误,崩溃发生在endMoveRows()调用处,未重写该方法。

问题代码

class IncidentTableModel(QAbstractTableModel):
     def moveRow(self, source_row, destination_row):

        if destination_row > -1 and destination_row < len(self.incidents):

            self.beginMoveRows(
                QModelIndex(),
                source_row,
                source_row,
                QModelIndex(),
                destination_row,
            )
            incident = self.incidents.pop(source_row)
            self.incidents.insert(destination_row, incident)

            self.endMoveRows()
        return True

class MainWindow(QMainWindow):
    # 正常工作
    def on_move_up_button_clicked(self):
        """Move selected table row up in table"""
        index = self.table_view.currentIndex()
        row = index.row()
        if row != -1:
            self.table_model.moveRow(row, row - 1)
            self.table_view.update()

    # 触发Segmentation Fault
    def on_move_down_button_clicked(self):
        """Move selected table row down in table"""
        index = self.table_view.currentIndex()

        if index.row() != -1 and index.row() < len(self.incidents) - 1:
            # index.row() + 2 能运行但会跳过一行,不符合需求
            self.table_model.moveRow(index.row(), index.row() + 1) 
            self.table_view.update()
            index = self.table_view.currentIndex()

原因分析

崩溃的核心问题是beginMoveRows()的参数使用错误:

  • 上移行时,source_row > destination_row,直接用destination_row作为插入位置是正确的,源行在目标位置下方,索引逻辑不会混乱。
  • 下移行时,source_row < destination_row,需要将插入位置设为destination_row + 1。因为Qt的beginMoveRows()中,destRow是插入点位置,移除源行后后续元素会前移,若直接用destination_row会导致索引重叠,触发内存访问错误。

解决方法

修改IncidentTableModel的moveRow方法,根据源行和目标行的位置关系调整插入位置参数,同时移除冗余的手动视图更新(endMoveRows()会自动通知视图刷新):

class IncidentTableModel(QAbstractTableModel):
     def moveRow(self, source_row, destination_row):
        # 边界校验:目标位置必须在有效范围内
        if destination_row < 0 or destination_row >= len(self.incidents):
            return False
        
        # 处理下移时的插入位置偏移
        dest_insert_pos = destination_row
        if source_row < destination_row:
            dest_insert_pos += 1

        self.beginMoveRows(
            QModelIndex(),
            source_row,
            source_row,
            QModelIndex(),
            dest_insert_pos,
        )
        # 调整数据列表
        incident = self.incidents.pop(source_row)
        self.incidents.insert(destination_row, incident)
        
        self.endMoveRows()
        return True

class MainWindow(QMainWindow):
    def on_move_up_button_clicked(self):
        index = self.table_view.currentIndex()
        row = index.row()
        if row > 0:  # 避免移到负数行
            self.table_model.moveRow(row, row - 1)
            # 更新选中索引
            self.table_view.setCurrentIndex(self.table_model.index(row - 1, 0))

    def on_move_down_button_clicked(self):
        index = self.table_view.currentIndex()
        row = index.row()
        max_row = len(self.table_model.incidents) - 1
        if row != -1 and row < max_row:
            self.table_model.moveRow(row, row + 1)
            # 更新选中索引
            self.table_view.setCurrentIndex(self.table_model.index(row + 1, 0))

额外优化点

  1. 上移时增加row > 0的判断,避免无效操作。
  2. 移动后手动更新选中索引,保持用户操作连贯性。
  3. 移除self.table_view.update(),endMoveRows()会自动触发视图更新,手动调用属于冗余操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 22:32:20