当我在mac上使用带有PyQT5和python3的QSortFilterProxy时,我总是得到一个segfault(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()
谢谢,提前
问题不是QSortFilterProxyModel,而是源模型的错误实现。另一方面,尽管使用layoutAboutToBeChanged解决问题并不是合适的选项,正如文档中所示,如果您想向模型添加行,则必须使用beginInsertRows()
和endInsertRows()
方法,这些方法将在内部调用layoutAboutToBeChanged信号,考虑到上述情况,最合适的实现是:
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"
发射一个"layoutAboutToBeChanged";换表时发出信号。
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.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()