How can I make it so when I click the Randomize button, for the selected treeview items, the treeview updates to show the changes to data, while maintaining the expanding items states and the users selection? Is this accomplished by subclasses the StandardItemModel or ProxyModel class? Help is much appreciated as I'm not sure how to resolve this issue.
It's a very simple example demonstrating the issue. When clicking Randmoize, all it's doing is randomly assigning a new string (name) to each coaches position on the selected Team.
import os
import sys
import random
from PySide2 import QtGui, QtWidgets, QtCore
class Team(object):
def __init__(self, name='', nameA='', nameB='', nameC='', nameD=''):
super(Team, self).__init__()
self.name = name
self.headCoach = nameA
self.assistantCoach = nameB
self.offensiveCoach = nameC
self.defensiveCoach = nameD
def randomize(self):
names = ['doug', 'adam', 'seth', 'emily', 'kevin', 'mike', 'sarah', 'cassy', 'courtney', 'henry']
cnt = len(names)-1
self.headCoach = names[random.randint(0, cnt)]
self.assistantCoach = names[random.randint(0, cnt)]
self.offensiveCoach = names[random.randint(0, cnt)]
self.defensiveCoach = names[random.randint(0, cnt)]
print('TRADED PLAYERS')
TEAMS = [
Team('Cowboys', 'doug', 'adam', 'seth', 'emily'),
Team('Packers'),
Team('Lakers', 'kevin', 'mike', 'sarah', 'cassy'),
Team('Yankees', 'courtney', 'henry'),
Team('Gators'),
]
class MainDialog(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
self.resize(600,400)
self.button = QtWidgets.QPushButton('Randomize')
self.itemModel = QtGui.QStandardItemModel()
self.proxyModel = QtCore.QSortFilterProxyModel()
self.proxyModel.setSourceModel(self.itemModel)
self.proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.proxyModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.proxyModel.setDynamicSortFilter(True)
self.proxyModel.setFilterKeyColumn(0)
self.treeView = QtWidgets.QTreeView()
self.treeView.setModel(self.proxyModel)
self.treeView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.treeView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.treeView.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.treeView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.treeView.setAlternatingRowColors(True)
self.treeView.setSortingEnabled(True)
self.treeView.setUniformRowHeights(False)
self.treeView.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.selectionModel = self.treeView.selectionModel()
# layout
self.mainLayout = QtWidgets.QVBoxLayout()
self.mainLayout.addWidget(self.treeView)
self.mainLayout.addWidget(self.button)
self.mainWidget = QtWidgets.QWidget()
self.mainWidget.setLayout(self.mainLayout)
self.setCentralWidget(self.mainWidget)
# connections
self.selectionModel.selectionChanged.connect(self.updateControls)
self.button.clicked.connect(self.randomizeTeams)
# begin
self.populateModel()
self.updateControls()
def randomizeTeams(self):
for proxyIndex in self.selectionModel.selectedRows():
sourceIndex = self.proxyModel.mapToSource(proxyIndex)
item = self.itemModel.itemFromIndex(sourceIndex)
team = item.data(QtCore.Qt.UserRole)
team.randomize()
# UPDATE UI...
def updateControls(self):
self.button.setEnabled(self.selectionModel.hasSelection())
def populateModel(self):
self.itemModel.clear()
self.itemModel.setHorizontalHeaderLabels(['Position', 'Name'])
# add teams
for ts in TEAMS:
col1 = QtGui.QStandardItem(ts.name)
col1.setData(ts, QtCore.Qt.UserRole)
# add coaches
childCol1 = QtGui.QStandardItem('Head Coach')
childCol1.setData(ts, QtCore.Qt.UserRole)
childCol2 = QtGui.QStandardItem(ts.headCoach)
col1.appendRow([childCol1, childCol2])
childCol1 = QtGui.QStandardItem('Head Coach')
childCol1.setData(ts, QtCore.Qt.UserRole)
childCol2 = QtGui.QStandardItem(ts.assistantCoach)
col1.appendRow([childCol1, childCol2])
childCol1 = QtGui.QStandardItem('Offensive Coach')
childCol1.setData(ts, QtCore.Qt.UserRole)
childCol2 = QtGui.QStandardItem(ts.offensiveCoach)
col1.appendRow([childCol1, childCol2])
childCol1 = QtGui.QStandardItem('Defensive Coach')
childCol1.setData(ts, QtCore.Qt.UserRole)
childCol2 = QtGui.QStandardItem(ts.defensiveCoach)
col1.appendRow([childCol1, childCol2])
self.itemModel.appendRow([col1])
self.itemModel.setSortRole(QtCore.Qt.DisplayRole)
self.itemModel.sort(0, QtCore.Qt.AscendingOrder)
self.proxyModel.sort(0, QtCore.Qt.AscendingOrder)
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainDialog()
window.show()
app.exec_()
if __name__ == '__main__':
pass
main()

Your
Teamclass should be a subclass ofQStandardItem, which will be the top-level parent in the model. This class should create its own child items (as you are currently doing in the for-loop ofpopulateModel), and itsrandomizemethod should directly reset the item-data of those children. This will ensure the changes are immediately reflected in the model.So - it's really just a matter of taking the code you already have and refactoring it accordingly. For example, something like this should work: