本文介绍了我如何从python中的模型中删除项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How do I properly remove items from my custom QAbstractTableModel? Do i need to change this to QStandardItemModel instead?

这是之前:

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

This is the after...it leaves empty rows and the selection doesn't seem to clear either.

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.rowCount())
        self.items = [x for x in self.items if x not in items]
        self.endRemoveRows()

    def clear(self):
        self.beginRemoveRows(QtCore.QModelIndex(), 0, 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() 行索引无效.

The reason for this behavior is that you're using the wrong row in beginRemoveRows(): you should use the row number you're removing, and since you're using rowCount() that row index is invalid.

    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()

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

To be more correct, you should remove the actual rows in the model. In your simple case it won't matter that much, but in case your model becomes more complex, keep in mind this.

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

The reason for the reversed row order in the for cycle is that for list consistency reasons the row removal should always begin from the bottom. This can be important if you want to remove rows arbitrarily while keeping the current selection in case the removed items are not selected.

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

That said, as already suggested in the comments, if you don't need specific behavior and implementation, creating a QAbstractItemModel (or any abstract model) subclass is unnecessary, as QStandardItemModel will usually be enough, as it already provides all required features (including drag and drop support, which can be rather complex if you don't know how the Qt data model works).
Well, unless it's for learning purposes, obviously.

这篇关于我如何从python中的模型中删除项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 19:43