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))
额外优化点
- 上移时增加
row > 0的判断,避免无效操作。 - 移动后手动更新选中索引,保持用户操作连贯性。
- 移除
self.table_view.update(),endMoveRows()会自动触发视图更新,手动调用属于冗余操作。
内容的提问来源于stack exchange,提问作者ab217
相关产品推荐
相关产品推荐

