2

I need to populate a listview with widgets, then have a custom proxyfilter work with it. Without the filter it works great, when active it seems to delete the widgets attach to the model.

It shows up fine showing all items, filtering works but when erasing the filter, when hidden widgets should be shown again following error gets thrown:

custom_widget.setGeometry(option.rect) RuntimeError: underlying C/C++ object has been deleted

Tried not using QVariant and going the internalPointer route but breaks at the same spot.

Thanks for having a look!

Setup:

def __init__(self, *args): 
    QtGui.QWidget.__init__(self, *args) 

    # create temp data
    self.list_data = []
    for x in xrange(500):
        widget = ListItemWidget(text=str(x), parent=self)
        self.list_data.append((str(x), widget)) # testing to put in inmut tuple

    # create listviewmodel
    self.lm = ListViewModel(parent=self)

    # create listview widget
    self.lv = QtGui.QListView()

    # create filter proxy     
    self.proxy_model = ListViewFilterProxyModel()
    self.proxy_model.setFilterPattern('')
    self.proxy_model.setSourceModel(self.lm)

    # set model of listview to filter proxy
    self.lv.setModel(self.proxy_model)

    # set delegate for column 0
    self.lv.setItemDelegateForColumn(0, CustomWidgetDelegate(self.lv))

    self.lm.updateData(self.list_data)
    self.proxy_model.invalidate()

    self.connect(self.filter_edit, QtCore.SIGNAL("textChanged(QString)"), self.update_filter)

    def update_filter(self, pattern):
        self.proxy_model.setFilterPattern(pattern)
        self.proxy_model.invalidate()

Custom widget

class ListItemWidget(QtGui.QWidget):
    def __init__(self, text=None, parent=None):
        QtGui.QWidget.__init__(self)      
        self.text = text

    @QtCore.pyqtProperty(QtCore.QString)
    def text(self):
        return self.__text

    @text.setter
    def text(self, value):
        self.__text = value

Delegate for painting the view

    class CustomWidgetDelegate(QtGui.QItemDelegate):
        def __init__(self, parent=None):
            super(CustomWidgetDelegate, self).__init__(parent)

        def paint(self, painter, option, index):   
            custom_widget = index.model().data(index, QtCore.Qt.DisplayRole).toPyObject()[1]
>>>>>>      custom_widget.setGeometry(option.rect)
            if not self.parent().indexWidget(index):
                self.parent().setIndexWidget(index, custom_widget)

List view model:

class ListViewModel(QtCore.QAbstractListModel): 
    def __init__(self, parent=None, *args): 
        QtCore.QAbstractListModel.__init__(self, parent, *args)
        self.listdata = []

    def rowCount(self, parent=QtCore.QModelIndex()): 
        return len(self.listdata) 

    def data(self, index, role): 
        if role == QtCore.Qt.SizeHintRole:
            return QtCore.QSize(80, 80)
        if index.isValid() and role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(self.listdata[index.row()]).toPyObject()
        return QtCore.QVariant()    

    def updateData(self, listdata):
        self.listdata = listdata
        index = len(self.listdata)
        return True

Finally the filter proxy model:

class ListViewFilterProxyModel(QtGui.QSortFilterProxyModel):
    def __init__(self, parent=None):
        self.filter_str = None
        QtGui.QSortFilterProxyModel.__init__(self, parent)

    def setFilterPattern(self, pattern):
        self.filter_str = QtCore.QString(pattern)

    def filterAcceptsRow(self, sourceRow, sourceParent):
        if self.filter_str is None:
            return True
        index = self.sourceModel().index(sourceRow, 0, sourceParent)  
        # just testing on the str here...
        text = index.data().toPyObject()[0]
        if not str(self.filter_str) in text:
            return False
        return True
4

0 回答 0