首页 > 解决方案 > 将委托分配给 TreeView 单元

问题描述

目前我正在创建一个 QTreeView ,其中第三列委托设置为 ComboBox 进行编辑。但是,我想让用户能够使用给定数据切换不同的视图,如下图所示。您如何建议我处理为指定单元格分配给正确行/列的组合框,如下图所示?

Flat List 版本效果很好,我不确定如何处理其他显示选项。

有没有办法将提供 QComboBox 的委托设置为每行/列的编辑器?

在此处输入图像描述

在此处输入图像描述

import os, sys, pprint
sys.path.append(os.environ.get('PS_SITEPACKAGES'))
from Qt import QtGui, QtWidgets, QtCore   
import pprint

class VersionProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        super(VersionProxyModel, self).__init__(*args, **kwargs)
        self.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)

    def checkParents(self, index):
        while (index.isValid()):
            if super(VersionProxyModel, self).filterAcceptsRow(index.row(), index.parent()):
                return True
            index = index.parent()
        return False

    def checkChildren(self, index):
        for i in range(0, self.sourceModel().rowCount(index)):
            if super(VersionProxyModel, self).filterAcceptsRow(i, index):
                return True

        # recursive
        for i in range(0, self.sourceModel().rowCount(index)):
            self.checkChildren(self.sourceModel().index(i, 0, index))

        return False 

    def filterAcceptsRow(self, source_row, parent):
        if super(VersionProxyModel, self).filterAcceptsRow(source_row, parent):
            return True

        if self.checkChildren(self.sourceModel().index(source_row, 0, parent)):
            return True

        return self.checkParents(parent)


class ComboBoxDelegate(QtWidgets.QStyledItemDelegate):
    def paint(self, painter, option, index):
        if isinstance(self.parent(), QtWidgets.QAbstractItemView):
             self.parent().openPersistentEditor(index)
        super(ComboBoxDelegate, self).paint(painter, option, index)

    def createEditor(self, parent, option, index):
        editor = QtWidgets.QComboBox(parent)
        editor.currentIndexChanged.connect(self.commitEditor)
        return editor

    @QtCore.Slot()
    def commitEditor(self):
        editor = self.sender()
        self.commitData.emit(editor)
        if isinstance(self.parent(), QtWidgets.QAbstractItemView):
            self.parent().updateEditorGeometries()

    def setEditorData(self, editor, index):
        values = index.data(QtCore.Qt.UserRole + 100)
        val = index.data(QtCore.Qt.UserRole + 101)
        editor.clear()
        for i, x in enumerate(values):
            editor.addItem(x['fullname'], x)
            if val['fullname'] == x['fullname']:
                editor.setCurrentIndex(i)

    def setModelData(self, editor, model, index):
        values = index.data(QtCore.Qt.UserRole + 100)
        ix = editor.currentIndex()
        model.setData(index, values[ix] , QtCore.Qt.UserRole + 101)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


class Window(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.resize(800, 400)

        self.FLATLIST = {   
            'Leslie': [
                    {'fullname': 'medic_skin_v001', 'entity': 'Medic', 'type': 'Bulky'}
                ],
            'Mike': [ 
                    {'fullname': 'tech_skin_v001', 'entity': 'Tech', 'type': 'Average'},
                    {'fullname': 'tech_skin_v002', 'entity': 'Tech', 'type': 'Average'}
                ],
            'Kevin': [ 
                    {'fullname': 'tech_skin_v001', 'entity': 'Tech', 'type': 'Average'},
                ],
            'Michelle': [
                    {'fullname': 'warrior_skin_v001', 'entity': 'Warrior', 'type': 'Athletic'},
                    {'fullname': 'warrior_skin_v002', 'entity': 'Warrior', 'type': 'Athletic'},
                    {'fullname': 'warrior_skin_v003', 'entity': 'Warrior', 'type': 'Athletic'}]
            }


        self.uiDisplayA = QtWidgets.QPushButton('Display Flat List')
        self.uiDisplayA.clicked.connect(self.slotDisplayA)

        self.uiDisplayB = QtWidgets.QPushButton('Display Grouped By Entity')
        self.uiDisplayB.clicked.connect(self.slotDisplayB)

        self.uiSearch = QtWidgets.QLineEdit()
        self.versionModel = QtGui.QStandardItemModel()
        self.versionProxyModel = VersionProxyModel()
        self.versionProxyModel.setSourceModel(self.versionModel)
        self.versionProxyModel.setDynamicSortFilter(True)
        self.uiVersionTreeView = QtWidgets.QTreeView()
        self.uiVersionTreeView.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.uiVersionTreeView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.uiVersionTreeView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.uiVersionTreeView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        self.uiVersionTreeView.setModel(self.versionProxyModel)
        # self.uiVersionTreeView.setRootIsDecorated(False)
        delegate = ComboBoxDelegate(self.uiVersionTreeView)
        self.uiVersionTreeView.setItemDelegateForColumn(3, delegate)
        # layout
        self.displayLayout = QtWidgets.QHBoxLayout()
        self.displayLayout.addWidget(self.uiDisplayA)
        self.displayLayout.addWidget(self.uiDisplayB)

        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addLayout(self.displayLayout)
        self.layout.addWidget(self.uiSearch)
        self.layout.addWidget(self.uiVersionTreeView)
        self.setLayout(self.layout)
        # signals/slots
        self.uiSearch.textChanged.connect(self.versionProxyModel.setFilterWildcard)
        self.slotDisplayA()


    def group_by_entity(self, items):
        grouped = {}
        for k, v in items.items():
            if not v: continue
            key = v[0].get('entity', 'unknown')
            if key not in grouped.keys():
                grouped[key] = {}
            grouped[key][k] = v
        return grouped


    def slotDisplayA(self):
        sortColumn = self.uiVersionTreeView.header().sortIndicatorSection()
        sortDirection = self.uiVersionTreeView.header().sortIndicatorOrder()
        self.versionModel.clear()
        self.uiVersionTreeView.setSortingEnabled(False)
        self.versionModel.setHorizontalHeaderLabels(['Entity', 'Type', 'Name', 'Versions'])


        for key, values in self.FLATLIST.items():
            col1 = QtGui.QStandardItem(values[0]['entity'])
            col2 = QtGui.QStandardItem(values[0]['type'])
            col3 = QtGui.QStandardItem(key)
            col4 = QtGui.QStandardItem()
            self.versionModel.appendRow([col1, col2, col3, col4])
            col2.setData(QtGui.QColor(80,150,200), role=QtCore.Qt.ForegroundRole)

            col4.setData(values, QtCore.Qt.UserRole + 100)
            col4.setData(values[0], QtCore.Qt.UserRole + 101)
        # Restore
        self.uiVersionTreeView.setSortingEnabled(True)
        self.uiVersionTreeView.sortByColumn(sortColumn, sortDirection)
        self.uiVersionTreeView.expandAll()
        for i in range(self.versionModel.columnCount()):
            self.uiVersionTreeView.resizeColumnToContents(i)


    def slotDisplayB(self):
        sortColumn = self.uiVersionTreeView.header().sortIndicatorSection()
        sortDirection = self.uiVersionTreeView.header().sortIndicatorOrder()
        self.versionModel.clear()
        self.uiVersionTreeView.setSortingEnabled(False)
        self.versionModel.setHorizontalHeaderLabels(['Type', 'Name', 'Versions'])

        # add each entity
        ENTIYLIST = self.group_by_entity(self.FLATLIST)

        pprint.pprint(ENTIYLIST, indent=4)
        for key, values in ENTIYLIST.items():
            parent = QtGui.QStandardItem(key)
            self.versionModel.appendRow(parent)

            # add entity children
            for childKey, childValues in values.items():
                child1 = QtGui.QStandardItem(childValues[0]['type'])
                child2 = QtGui.QStandardItem(childKey)
                child3 = QtGui.QStandardItem()
                parent.appendRow([child1, child2, child3])
                child1.setData(QtGui.QColor(80,150,200), role=QtCore.Qt.ForegroundRole)

        # Restore
        self.uiVersionTreeView.setSortingEnabled(True)
        self.uiVersionTreeView.sortByColumn(sortColumn, sortDirection)
        self.uiVersionTreeView.expandAll()
        for i in range(self.versionModel.columnCount()):
            self.uiVersionTreeView.resizeColumnToContents(i)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = Window()
    ex.show()
    app.exec_()

标签: pythonpysideqtreeview

解决方案


推荐阅读