add feature for previous question PySide2 QListView and QTableView

99封情书 提交于 2019-12-24 10:15:12

问题


The previous question was PySide2 QListView QTableView sync problem

Imagine to have another dict4 in the data structure:

'dict4':{'k8':'v8', 'EXISTING_DICT':'dict2'},

Meaning, that a dictionary could include another existing dictionary.

So the representation in the QTableView shouldn't be directly showed, but:

1) Show just the name of it in the QTableView:

k1 | v1
-------
k2 | v2
-------
k3 | v3
-------
dict2

2) If double click it on it: select the existing dictionary in the QListView, which will trigger to show its contents in the QTableView, which in this case:

k4 | v4

回答1:


In this case the idea is to use a role to indicate that the field points to another item, then use setSpan to join items and finally check if the item selected in the QTableView points to another element by selecting if it is so

from PySide2 import QtCore, QtGui, QtWidgets

dict_of_dicts={
    'dict1':{'k1':'v1', 'k2':'v2', 'k3':'v3', 'EXISTING_DICT': 'dict3'},
    'dict2':{'k4':'v4', 'EXISTING_DICT': 'dict1'},
    'dict3':{'k5':'v5', 'k6':'v6', 'k7':'v7', 'EXISTING_DICT': 'dict4'},
    'dict4':{'k8':'v8', 'EXISTING_DICT':'dict2'},
}

def create_model_from_dict(d, parent=None):
    model = QtGui.QStandardItemModel(0, 2, parent)
    for k, v in dict_of_dicts.items():
        it = QtGui.QStandardItem(k)
        model.appendRow(it)
        for k_, v_ in v.items():
            if k_ != "EXISTING_DICT":
                it.appendRow([QtGui.QStandardItem(k_), QtGui.QStandardItem(v_)])
            else:
                child_it = QtGui.QStandardItem(v_)
                child_it.setTextAlignment(QtCore.Qt.AlignCenter)
                child_it.setData(True, QtCore.Qt.UserRole + 1000)
                it.appendRow(child_it)
    return model

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        model = create_model_from_dict(dict_of_dicts, self)

        self.tableview = QtWidgets.QTableView()
        self.tableview.setModel(model)
        self.tableview.selectionModel().selectionChanged.connect(self.handleSelectionChangedTV)

        self.listview = QtWidgets.QListView()
        self.listview.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.listview.setModel(model)
        self.listview.selectionModel().selectionChanged.connect(self.handleSelectionChangedLV)
        self.listview.selectionModel().select(model.index(0, 0), QtCore.QItemSelectionModel.Select)

        hlay = QtWidgets.QHBoxLayout(self)
        hlay.addWidget(self.listview)
        hlay.addWidget(self.tableview)

    @QtCore.Slot(QtCore.QItemSelection)
    def handleSelectionChangedLV(self, item):
        ixs = item.indexes()
        if ixs:
            self.tableview.setRootIndex(ixs[0])
            model = self.tableview.model()
            self.tableview.clearSpans()
            for r in range(model.rowCount(self.tableview.rootIndex())):
                index = model.index(r, 0, self.tableview.rootIndex())
                if index.data(QtCore.Qt.UserRole + 1000):
                    self.tableview.setSpan(r, 0, 1, 2)

    @QtCore.Slot(QtCore.QItemSelection)
    def handleSelectionChangedTV(self, item):
        ixs = item.indexes()
        if ixs:
            ix = ixs[0]
            if ix.data(QtCore.Qt.UserRole + 1000):
                items = self.listview.model().findItems(ix.data())
                if items:
                    self.tableview.clearSelection()
                    self.listview.selectionModel().select(items[0].index(), QtCore.QItemSelectionModel.ClearAndSelect)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

UPDATE:

from PySide2 import QtCore, QtGui, QtWidgets

dict_of_dicts={
    'dict1':{'k1':'v1', 'k2':'v2', 'k3':'v3', 'EXISTING_DICT': 'dict3'},
    'dict2':{'k4':'v4', 'EXISTING_DICT': 'dict1'},
    'dict3':{'k5':'v5', 'k6':'v6', 'k7':'v7', 'EXISTING_DICT': 'dict4'},
    'dict4':{'k8':'v8', 'EXISTING_DICT':'dict2'},
}

def create_model_from_dict(d, parent=None):
    model = QtGui.QStandardItemModel(0, 2, parent)
    for k, v in dict_of_dicts.items():
        it = QtGui.QStandardItem(k)
        model.appendRow(it)
        for k_, v_ in v.items():
            if k_ != "EXISTING_DICT":
                it.appendRow([QtGui.QStandardItem(k_), QtGui.QStandardItem(v_)])
            else:
                child_it = QtGui.QStandardItem(v_)
                child_it.setTextAlignment(QtCore.Qt.AlignCenter)
                child_it.setData(True, QtCore.Qt.UserRole + 1000)
                it.appendRow(child_it)
    return model

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        model = create_model_from_dict(dict_of_dicts, self)

        self.tableview = QtWidgets.QTableView()
        self.tableview.setModel(model)
        self.tableview.doubleClicked.connect(self.handleSelectionChangedTV)

        self.listview = QtWidgets.QListView()
        self.listview.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.listview.setModel(model)
        self.listview.selectionModel().selectionChanged.connect(self.handleSelectionChangedLV)
        self.listview.selectionModel().select(model.index(0, 0), QtCore.QItemSelectionModel.Select)

        hlay = QtWidgets.QHBoxLayout(self)
        hlay.addWidget(self.listview)
        hlay.addWidget(self.tableview)

    @QtCore.Slot(QtCore.QItemSelection)
    def handleSelectionChangedLV(self, item):
        ixs = item.indexes()
        if ixs:
            self.tableview.setRootIndex(ixs[0])
            model = self.tableview.model()
            self.tableview.clearSpans()
            for r in range(model.rowCount(self.tableview.rootIndex())):
                index = model.index(r, 0, self.tableview.rootIndex())
                if index.data(QtCore.Qt.UserRole + 1000):
                    self.tableview.setSpan(r, 0, 1, 2)

    @QtCore.Slot(QtCore.QModelIndex)
    def handleSelectionChangedTV(self, ix):
        if ix.data(QtCore.Qt.UserRole + 1000):
            items = self.listview.model().findItems(ix.data())
            if items:
                self.tableview.clearSelection()
                self.listview.selectionModel().select(items[0].index(), QtCore.QItemSelectionModel.ClearAndSelect)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

UPDATE2

from PySide2 import QtCore, QtGui, QtWidgets

dict_of_dicts={
    'dict1':{'k1':'v1', 'k2':'v2', 'k3':'v3', 'EXISTING_DICT': 'dict3'},
    'dict2':{'k4':'v4', 'EXISTING_DICT': 'dict1'},
    'dict3':{'k5':'v5', 'k6':'v6', 'k7':'v7', 'EXISTING_DICT': 'dict4'},
    'dict4':{'k8':'v8', 'EXISTING_DICT':'dict2'},
}

def create_model_from_dict(d, parent=None):
    model = QtGui.QStandardItemModel(0, 2, parent)
    for k, v in dict_of_dicts.items():
        it = QtGui.QStandardItem(k)
        model.appendRow(it)
        for k_, v_ in v.items():
            if k_ != "EXISTING_DICT":
                it.appendRow([QtGui.QStandardItem(k_), QtGui.QStandardItem(v_)])
            else:
                child_it = QtGui.QStandardItem(v_)
                child_it.setTextAlignment(QtCore.Qt.AlignCenter)
                child_it.setData(True, QtCore.Qt.UserRole + 1000)
                it.appendRow(child_it)
    return model

class TableView(QtWidgets.QTableView):
    leftDoubleClicked = QtCore.Signal(QtCore.QModelIndex)

    def mouseDoubleClickEvent(self, event):
        super(TableView, self).mouseDoubleClickEvent(event)
        if event.buttons() & QtCore.Qt.LeftButton:
            ix = self.indexAt(event.pos())
            if ix.isValid(): self.leftDoubleClicked.emit(ix)

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        model = create_model_from_dict(dict_of_dicts, self)

        self.tableview = TableView()
        self.tableview.setModel(model)
        self.tableview.leftDoubleClicked.connect(self.handleSelectionChangedTV)

        self.listview = QtWidgets.QListView()
        self.listview.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.listview.setModel(model)
        self.listview.selectionModel().selectionChanged.connect(self.handleSelectionChangedLV)
        self.listview.selectionModel().select(model.index(0, 0), QtCore.QItemSelectionModel.Select)

        hlay = QtWidgets.QHBoxLayout(self)
        hlay.addWidget(self.listview)
        hlay.addWidget(self.tableview)

    @QtCore.Slot(QtCore.QItemSelection)
    def handleSelectionChangedLV(self, item):
        ixs = item.indexes()
        if ixs:
            self.tableview.setRootIndex(ixs[0])
            model = self.tableview.model()
            self.tableview.clearSpans()
            for r in range(model.rowCount(self.tableview.rootIndex())):
                index = model.index(r, 0, self.tableview.rootIndex())
                if index.data(QtCore.Qt.UserRole + 1000):
                    self.tableview.setSpan(r, 0, 1, 2)

    @QtCore.Slot(QtCore.QModelIndex)
    def handleSelectionChangedTV(self, ix):
        if ix.data(QtCore.Qt.UserRole + 1000):
            items = self.listview.model().findItems(ix.data())
            if items:
                self.tableview.clearSelection()
                self.listview.selectionModel().select(items[0].index(), QtCore.QItemSelectionModel.ClearAndSelect)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/54019582/add-feature-for-previous-question-pyside2-qlistview-and-qtableview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!