首页 > 解决方案 > 使用 QSortFilterProxyModel 时的 pyQt5 段错误

问题描述

在我的 Mac 上将 QSortFilterProxy 与 PyQT5 和 python3 一起使用时,我一直遇到段错误 (11)。

该表按预期出现,并且能够很好地排序。但是,当添加一个项目,然后尝试进行后续排序时,gui 会因“segfault 11”而崩溃

我的研究没有成果。我希望这里有人可以提供帮助。以下代码是一个简单的示例。

#! /Library/Frameworks/Python.framework/Versions/3.8/bin/python3

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QObject
from PyQt5.QtWidgets import (QApplication,
                             QTableView, QWidget,QPushButton,
                             QVBoxLayout,QMainWindow)

import sys

class MyModel(QtCore.QAbstractTableModel) :
   def __init__(self,data=None,parent = None, *args) :
      super(MyModel,self).__init__(parent,*args) 
      
      self.data = data or []
     
   #Add item to the data. 
   def addItem(self,item) :
        
      #add the item to to the model data.
      self.data.append(item)
     
      #Emit signal to the TableView to redraw
      self.layoutChanged.emit()
        
   #Overloaded function that must be defined.      
   def data(self,index,role) :
      #The index (contains both x,y) and role are passed.  
      #The roles give instructions about how to display the model.
      row = index.row()
      col = index.column()
      
      #Insert the appropriate information into the display, based
      #on the column. 
      if role == Qt.DisplayRole :
         item = self.data[row]         
         if (col == 0) :
            return(item.name)
         if (col == 1) :  
            return(item.num)
  
   #rowCount must be overloaded
   def rowCount(self,index) :
      return(len(self.data))
   
   #columnCount must be overloaded
   def columnCount(self,index) :      
      return(2)
   
   #Display headers for the columns
   def headerData(self,section,orientation,role) :
      if (role != Qt.DisplayRole) :
         return
      if (orientation != Qt.Horizontal) :
         return      
      if (section == 0) :
         return("Name")
      if (section == 1) :
         return("Number")
      

class MainWindow(QtWidgets.QMainWindow) :
   def __init__(self,*args,**kwargs) :
      super(MainWindow,self).__init__(*args,**kwargs)
      
      self.data = [] 
 
      proxymodel = QtCore.QSortFilterProxyModel()
      proxymodel.setDynamicSortFilter(True)
      proxymodel.setFilterKeyColumn(0)
      self.proxymodel = proxymodel
      
      #Create the TableView widget that will display the model
      self.mytable = QtWidgets.QTableView()
      self.mytable.setSortingEnabled(True)
           
      #Create the model that will be displayed in the table
      self.mymodel = MyModel(self.data)
      #Assign the model to the table
      self.mytable.setModel(proxymodel)
      
      self.proxymodel.setSourceModel(self.mymodel)
      #Put the table in the main widget's layout.
      #Need to have a layout for its size hint.
      layout = QtWidgets.QHBoxLayout()
      layout.addWidget(self.mytable,0,Qt.AlignHCenter)
      
      button = QPushButton("Add Item",self)
      button.clicked.connect(self.addItem) 
      layout.addWidget(button)
      
      self.layout = layout
      
      #The actual widget. 
      widget = QtWidgets.QWidget()
      widget.setLayout(layout)                    
      
      #Show the results
      self.setCentralWidget(widget)
      self.show()
      
      for i in range(10) :
         item = Item(i)
         self.mymodel.addItem(item)
         
   def addItem(self) :
      num = len(self.mymodel.data)
      item = Item(num)
      self.mymodel.addItem(item)
      
app = QtWidgets.QApplication(sys.argv)

window = MainWindow()
app.exec()

提前致谢

标签: pythonpython-3.xsegmentation-faultpyqt5qsortfilterproxymodel

解决方案


问题不是 QSortFilterProxyModel 而是源模型的错误实现。另一方面,虽然使用 layoutAboutToBeChanged 解决问题不是合适的选项,如文档中所述,如果您想向模型添加行,那么您必须使用将在内部调用 layoutAboutToBeChanged 信号的beginInsertRows()andendInsertRows()方法,考虑到上述情况,最合适的实现是:

class MyModel(QtCore.QAbstractTableModel):
    def __init__(self, data=None, parent=None, *args):
        super(MyModel, self).__init__(parent, *args)

        self.data = data or []

    # Add item to the data.
    def addItem(self, item):
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        self.data.append(item)
        self.endInsertRows()

    def data(self, index, role):
        if not index.isValid():
            return
        row = index.row()
        col = index.column()
        if (row < 0 or row >= self.rowCount()) and (
            col < 0 or col >= self.columnCount()
        ):
            return

        if role == Qt.DisplayRole:
            item = self.data[row]
            if col == 0:
                return item.name
            if col == 1:
                return item.num

    def rowCount(self, index=QtCore.QModelIndex()):
        return len(self.data)

    def columnCount(self, index=QtCore.QModelIndex()):
        return 2

    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole:
            return
        if orientation != Qt.Horizontal:
            return
        if section == 0:
            return "Name"
        if section == 1:
            return "Number"

推荐阅读