在PySid中显示两组相互依赖的数据的abstractTableModel

2024-09-23 16:17:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在为电影摄影构建一个python/PySide工具。我创造了一个物体代表一个镜头。它具有开始时间、结束时间的属性,以及对actor对象的引用列表。actor对象具有简单的属性(名称、构建、年龄等),并且可以在快照之间共享。在

我想在PySide的两个表视图中显示这个。一个表视图列出了快照(和列中的属性),而另一个表视图则显示了所选快照中引用的参与者。如果未选择快照,则第二个表视图为空。如果选择了多个快照,则所有引用的角色都将显示在actor table视图中。在

我为我的快照数据创建了一个abstractTableModel,并且在其对应的表视图中,快照数据的一切都正常工作。然而,我甚至不知道如何处理参与者的表视图。我应该为演员使用另一个抽象表模型吗?我似乎不知道如何使用abstractTableModel将数据馈送/连接到第二个表视图,以供选定镜头中包含的参与者使用。在

我认为我的部分问题是我只想显示一次演员信息,而不管多个选定镜头是否引用同一个演员。在多次失败的尝试之后,我认为我需要将所选的快照信息(它们的actor list属性)重定向并解析到主窗口的一个自定义属性中,以包含一个包含所有引用的actor索引的列表,并创建一个abstractTableModel,该模型使用它获取实际的actor属性以进行显示。我不完全相信这会奏效,更不用说我的直觉告诉我这是一个混乱的方法,所以我来这里寻求建议。在

这是正确的方法吗?如果不是,那么在PySide/python中设置它的“正确”方法是什么。在

请记住,这是我第一次涉足数据模型和PySide。在

这是镜头模型。在

class ShotTableModel(QtCore.QAbstractTableModel):
    def __init__(self, data=[], parent=None, *args):
        super(ShotTableModel, self).__init__(parent)
        self._data = data

    def rowCount(self, parent):
        return len(self._data.shots)

    def columnCount(self, parent):
        return len(self._data._headers_shotList)

    def getItemFromIndex(self, index):
        if index.isValid():
            item = self._data.shots[index.row()]   
            if item:
                return item
        return None

    def flags(self, index):
        if index.isValid():
            item = self.getItemFromIndex(index)
            return item.qt_flags(index.column())

    def data(self, index, role):
        if not index.isValid():
            return None

        item = self.getItemFromIndex(index)

        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            return item.qt_data(index.column())

        if role == QtCore.Qt.CheckStateRole:
            if index.column() is 0:
                return item.qt_checked

#         if role == QtCore.Qt.BackgroundColorRole:
#             return QtGui.QBrush()

#         if role == QtCore.Qt.FontRole:
#             return QtGui.QFont()

        if role == QtCore.Qt.DecorationRole:
            if index.column() == 0:
                resource = item.qt_resource()
                return QtGui.QIcon(QtGui.QPixmap(resource))

        if role == QtCore.Qt.ToolTipRole:
            return item.qt_toolTip()

        return None

    def setData(self, index, value, role = QtCore.Qt.EditRole):
        if index.isValid():
            item = self.getItemFromIndex(index)
            if role == QtCore.Qt.EditRole:
                item.qt_setData(index.column(), value)
                self.dataChanged.emit(index, index)
                return value

            if role == QtCore.Qt.CheckStateRole:
                if index.column() is 0:
                    item.qt_checked = value
                    return True
        return value

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

    def insertRows(self, position, rows, parent = QtCore.QModelIndex()):
        self.beginInsertRows(parent, position, position + rows - 1)
        for row in range(rows):
            newShotName = self._data.getUniqueName(self._data.shots, 'New_Shot')
            newShot = Shot(newShotName)
            self._data.shots.insert(position, newShot)
        self.endInsertRows()
        return True

    def removeRows(self, position, rows, parent = QtCore.QModelIndex()):
        self.beginRemoveRows(parent, position, position + rows - 1)
        for row in range(rows):
            self._data.shots.pop(position)   
        self.endRemoveRows()
        return True

这是包含shot和actor实例的数据块。这是我传给模特的。在

^{pr2}$

最后是主要工具。在

class ShotManager(form, base):
    def __init__(self, parent=None):
        super(ShotManager, self).__init__(parent)
        self.setupUi(self)

        #=======================================================================
        # Properties
        #=======================================================================


        self.data = ShotManagerData() #do any loading if necessary here
        self.actorsInSelectedShots = []

        #test data
        actor1 = Actor('Actor1')
        actor2 = Actor('Actor2')
        actor3 = Actor('Actor3')

        shot1 = Shot('Shot1', [actor1, actor2])
        shot2 = Shot('Shot2', [actor2, actor3])
        shot3 = Shot('Shot3', [actor1])

        self.data.actors.append(actor1)
        self.data.actors.append(actor2)   
        self.data.actors.append(actor3)

        self.data.shots.append(shot1)
        self.data.shots.append(shot2)
        self.data.shots.append(shot3)

        #=======================================================================
        # Models
        #=======================================================================
        self._model_shotList = ShotTableModel(self.data)
        self._proxyModel_shotList = QtGui.QSortFilterProxyModel()
        self._proxyModel_shotList.setSourceModel(self._model_shotList)
        self.shotList.setModel(self._proxyModel_shotList)  #this is the QTableView
        self._selModel_shotList = self.shotList.selectionModel()
        self.shotList.setSortingEnabled(True)
        self._proxyModel_shotList.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)


        self._model_actorList = SelectedShotsActorTableModel(self.data)
        self._proxyModel_actorList = QtGui.QSortFilterProxyModel()
        self._proxyModel_actorList.setSourceModel(self._model_actorList)
        self.actorList.setModel(self._proxyModel_actorList)
        self._selModel_actorList = self.actorList.selectionModel()

        #=======================================================================
        # Events
        #=======================================================================
        self.addShot.clicked.connect(self.addShot_clicked)
        self.delShot.clicked.connect(self.delShot_clicked)


        self._selModel_shotList.selectionChanged.connect(self.shotList_selectionChanged)

    #===========================================================================
    # General Functions    
    #===========================================================================
    def getSelectedRows(self, widget):
        selModel = widget.selectionModel()
        proxyModel = widget.model()
        model = proxyModel.sourceModel()
        rows = [proxyModel.mapToSource(index).row() for index in selModel.selectedRows()]
        rows.sort()
        return rows

    def getSelectedItems(self, widget):
        selModel = widget.selectionModel()
        proxyModel = widget.model()
        model = proxyModel.sourceModel()
        indices = [proxyModel.mapToSource(index) for index in selModel.selectedRows()]
        items = [model.getItemFromIndex(index) for index in indices]
        return items
    #===========================================================================
    # Event Functions    
    #===========================================================================
    def addShot_clicked(self):
        position = len(self.data.shots)
        self._proxyModel_shotList.insertRows(position,1)

    def delShot_clicked(self):
        rows = self.getSelectedRows(self.shotList)
        for row in reversed(rows):
            self._proxyModel_shotList.removeRows(row, 1)

    def shotList_selectionChanged(self, selected, deselected):
        selectedShots = self.getSelectedItems(self.shotList)
        print 'SelectedShots: {}'.format(selectedShots)
        self.data.selectedShotsActors = self.data.actorsOfShots(selectedShots)
        print 'ActorsOfShots: {}'.format(self.data.selectedShotsActors)

        self._proxyModel_actorList.setData() # this line reports missing variables

这是selectedShotActors模型:

class SelectedShotsActorTableModel(QtCore.QAbstractTableModel):
    def __init__(self, data=[], headers=[], parent=None, *args):
        super(SelectedShotsActorTableModel, self).__init__(parent)
        self._data = data

    def rowCount(self, parent):
        return len(self._data.selectedShotsActors)

    def columnCount(self, parent):
        return len(self._data._headers_actorList)

    def getItemFromIndex(self, index):
        if index.isValid():
            item = self._data.selectedShotsActors[index.row()]   
            if item:
                return item
        return None

    def flags(self, index):
        if index.isValid():
            item = self.getItemFromIndex(index)
            return item.qt_flags(index.column())

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

        item = self.getItemFromIndex(index)
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            return item.qt_data(index.column())

        if role == QtCore.Qt.CheckStateRole:
            if index.column() is 0:
                return item.qt_checked
#         
#         if role == QtCore.Qt.BackgroundColorRole:
#             return QtGui.QBrush()
#         
#         if role == QtCore.Qt.FontRole:
#             return QtGui.QFont()

        if role == QtCore.Qt.DecorationRole:
            if index.column() == 0:
                resource = item.qt_resource()
                return QtGui.QIcon(QtGui.QPixmap(resource))

        if role == QtCore.Qt.ToolTipRole:
            return item.qt_toolTip()

    def setData(self, index, value, role = QtCore.Qt.EditRole):
        if index.isValid():
            item = self.getItemFromIndex(index)
            if role == QtCore.Qt.EditRole:
                item.qt_setData(index.column(), value)
                self.dataChanged.emit(index, index)
                return value
            if role == QtCore.Qt.CheckStateRole:
                if index.column() is 0:
                    item.qt_checked = value
                    return True
        return value

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

Tags: selfdataindexreturnifdefcolumnitem
2条回答

我建议你使用代理模型。代理模型不保存数据,它们链接到一个现有的模型,并根据需要提供对数据进行排序、筛选或重组的机会。在

具体来说,您可以创建一个QSortFilterProxyModel对象,其中QTableView的{}作为源。然后,可以创建一个自定义过滤器,该过滤器基于选定的快照构造一个演员列表。这种方法的优点是代理模型和视图将随着选择的更改而自动更新。我认为这种方法比向主窗口添加代码更符合MVC的意图。在

有关如何执行此操作的详细信息,请参阅自定义排序/筛选模型示例。 http://qt-project.org/doc/qt-5/qtwidgets-itemviews-customsortfiltermodel-example.html

如果您需要一些背景信息(我也是Qt-MVC的新手;我感觉到了您的痛苦),以下是一些其他有用的链接:

模型视图编程:代理模型 http://qt-project.org/doc/qt-5/model-view-programming.html#proxy-models

QSortFilterProxyModel http://qt-project.org/doc/qt-5/qsortfilterproxymodel.html

我的建议是根据您拍摄的selectionChanged()信号更新actor模型selectionModel。在

每次发出信号时(当快照选择发生更改时),您需要重置actor模型,然后在选择范围内迭代选定的模型索引,并为模型的每个选定行获取对快照对象的引用。对于每个拍摄对象,你可以得到一个演员名单。然后需要检查actor是否在actor模型中,如果不在actor模型中,则添加它。在

现在这有点低效,因为每次更改快照模型的选择时都要重置actor模型。您确实从selectionChanged()信号中获得了有关哪些行被取消选择的信息,因此您可以在重新取消选择快照模型的行时从参与者模型中删除条目,,但前提是没有其他选定的快照行包含您取消选择的快照中的给定actor。在

对于这些代码在您的项目中的位置,有一些选项,但是我可能会选择,但是在您已经可以访问演员和镜头的视图和模型的情况下。在没有qmain代码的情况下,很难看到它!在

希望有帮助:)

相关问题 更多 >