我如何从python中的模型中删除项目

问题描述

如何从我的自定义 QAbstractTableModel 中正确删除项目?我需要将其改为 QStandardItemModel 吗?

这是之前:

enter image description here

这是之后...它留下空行并且选择似乎也没有清除。

enter image description here

import os
import sys
from PySide import QtCore,QtGui
import random


class CustomJobs(object):

    def __init__(self,**kwargs):
        super(CustomJobs,self).__init__()

        # instance properties
        self.name = ''
        self.status = ''

        # initialize attribute values
        for k,v in kwargs.items():
            if hasattr(self,k):
                setattr(self,k,v)


class PlayblastTableModel(QtCore.QAbstractTableModel):

    HEADERS = ['Name','Status']

    def __init__(self):
        super(PlayblastTableModel,self).__init__()
        self.items = []

    def headerData(self,section,orientation,role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal:
            if role == QtCore.Qt.DisplayRole:
                return self.HEADERS[section]
        return None

    def columnCount(self,parent=QtCore.QModelIndex()):
        return len(self.HEADERS)

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

    def addItem(self,*items):
        self.beginInsertRows(QtCore.QModelIndex(),self.rowCount(),self.rowCount() + len(items) - 1)
        for item in items:
            assert isinstance(item,CustomJobs)
            self.items.append(item)
        self.endInsertRows()

    def removeItems(self,items):
        self.beginRemoveRows(QtCore.QModelIndex(),self.rowCount())
        self.items = [x for x in self.items if x not in items]
        self.endRemoveRows()

    def clear(self):
        self.beginRemoveRows(QtCore.QModelIndex(),self.rowCount())
        self.items = []
        self.endRemoveRows()

    def data(self,index,role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return

        row = index.row()
        col = index.column()

        if 0 <= row < self.rowCount():
            item = self.items[row]

            if role == QtCore.Qt.DisplayRole:
                if col == 0:
                    return item.name
                elif col == 1:
                    return item.status.title()
            elif role == QtCore.Qt.UserRole:
                return item

        return None


class CustomJobsQueue(QtGui.QWidget):
    '''
    Description:
        Widget that manages the Jobs Queue
    '''
    def __init__(self):
        super(CustomJobsQueue,self).__init__()
        self.resize(400,600)

        # controls
        self.uiAddNewJob = QtGui.QPushButton('Add')
        self.uiRemoveSelectedJobs = QtGui.QPushButton('Remove')

        self.playblastJobModel = PlayblastTableModel()
        self.uiJobTableView = QtGui.QTableView()
        self.uiJobTableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.uiJobTableView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.uiJobTableView.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.uiJobTableView.setModel(self.playblastJobModel)

        self.jobSelection = self.uiJobTableView.selectionModel()

        # sub layouts
        self.jobQueueToolsLayout = QtGui.QHBoxLayout()
        self.jobQueueToolsLayout.addWidget(self.uiAddNewJob)
        self.jobQueueToolsLayout.addWidget(self.uiRemoveSelectedJobs)
        self.jobQueueToolsLayout.addStretch()

        # layout
        self.mainLayout = QtGui.QVBoxLayout()
        self.mainLayout.addLayout(self.jobQueueToolsLayout)
        self.mainLayout.addWidget(self.uiJobTableView)
        self.setLayout(self.mainLayout)

        # connections
        self.uiAddNewJob.clicked.connect(self.addNewJob)
        self.uiRemoveSelectedJobs.clicked.connect(self.removeSelectedJobs)


    # methods
    def addNewJob(self):
        name = random.choice(['Kevin','Suzie','Melissa'])
        status = random.choice(['error','warning','successa'])
        job = CustomJobs(name=name,status=status)
        self.playblastJobModel.addItem(job)

    def removeSelectedJobs(self):
        jobs = self.getSelectedJobs()
        self.playblastJobModel.removeItems(jobs)

    def getSelectedJobs(self):
        jobs = [x.data(QtCore.Qt.UserRole) for x in self.jobSelection.selectedRows()]
        return jobs


def main():
    app = QtGui.QApplication(sys.argv)
    window = CustomJobsQueue()
    window.show()
    app.exec_()


if __name__ == '__main__':
    main()

解决方法

这种行为的原因是您在 beginRemoveRows() 中使用了错误的行:您应该使用要删除的行号,并且由于您使用的是 rowCount(),因此行索引是无效。

    def removeItems(self,items):
        self.beginRemoveRows(QtCore.QModelIndex(),self.rowCount() - 1,self.rowCount() - 1)
        self.items = [x for x in self.items if x not in items]
        self.endRemoveRows()

为了更正确,您应该删除模型中的实际行。在您的简单情况下,这并不重要,但如果您的模型变得更复杂,请记住这一点。

    def removeItems(self,items):
        removeRows = []
        for row,item in enumerate(self.items):
            if item in items:
                removeRows.append(row)
        for row in sorted(removeRows,reverse=True):
            self.beginRemoveRows(QtCore.QModelIndex(),row,row)
            self.items.pop(row)
            self.endRemoveRows()

for 循环中行顺序颠倒的原因是,出于列表一致性的原因,行删除应始终从底部开始。如果您想在保留当前选择的同时任意删除行以防未选择删除的项目,这可能很重要。

也就是说,正如评论中已经建议的那样,如果您不需要特定的行为和实现,则不需要创建 QAbstractItemModel(或任何抽象模型)子类,因为 QStandardItemModel 通常就足够了,因为它已经提供了所有必需的功能(包括拖放支持,如果您不知道 Qt 数据模型的工作原理,这可能会相当复杂)。
好吧,除非是出于学习目的,显然。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...