Using the identical question asked about QListWidgets as a guide, I am trying to make a QStandardItemModel
in which I can undo the edit of an item.
As can be seen in the SSCCE below, I'm pretty much copying the example exactly, but with some minor tweaking because currentItemChanged
isn't available for QStandardItemModel
. To get around that, I'm using the clicked
signal instead to fix the previous text for an item.
Strangely, the correct description shows up in the undostack, but when I click the undo
button it doesn't actually undo anything.
Note the present question is superficially the same as this question. The answer that was accepted at that other version is less an answer, more a hint. It's a hint I am trying to implement here, but it is not working yet. Since this question is more specific and detailed, it shouldn't count as a duplicate, IMO.
SSCCE
from PySide import QtGui, QtCore
import sys
class CommandItemEdit(QtGui.QUndoCommand):
def __init__(self, model, item, textBeforeEdit, description = "Item edited"):
QtGui.QUndoCommand.__init__(self, description)
self.model = model
self.item = item
self.textBeforeEdit = textBeforeEdit
self.textAfterEdit = item.text()
def redo(self):
self.model.blockSignals(True)
self.item.setText(self.textAfterEdit)
self.model.blockSignals(False)
def undo(self):
self.model.blockSignals(True)
self.item.setText(self.textBeforeEdit)
self.model.blockSignals(False)
class UndoableTree(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent = None)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.view = QtGui.QTreeView()
self.model = self.createModel()
self.view.setModel(self.model)
self.view.expandAll()
self.undoStack = QtGui.QUndoStack(self)
undoView = QtGui.QUndoView(self.undoStack)
buttonLayout = self.buttonSetup()
mainLayout = QtGui.QHBoxLayout(self)
mainLayout.addWidget(undoView)
mainLayout.addWidget(self.view)
mainLayout.addLayout(buttonLayout)
self.setLayout(mainLayout)
self.makeConnections()
#For undo/redo editing
self.textBeforeEdit = ""
def makeConnections(self):
self.view.clicked.connect(self.itemClicked)
self.model.itemChanged.connect(self.itemChanged)
self.quitButton.clicked.connect(self.close)
self.undoButton.clicked.connect(self.undoStack.undo)
self.redoButton.clicked.connect(self.undoStack.redo)
def itemClicked(self, index):
item = self.model.itemFromIndex(index)
self.textBeforeEdit = item.text()
def itemChanged(self, item):
command = CommandItemEdit(self.model, item, self.textBeforeEdit,
"Renamed '{0}' to '{1}'".format(self.textBeforeEdit, item.text()))
self.undoStack.push(command)
def buttonSetup(self):
self.undoButton = QtGui.QPushButton("Undo")
self.redoButton = QtGui.QPushButton("Redo")
self.quitButton = QtGui.QPushButton("Quit")
buttonLayout = QtGui.QVBoxLayout()
buttonLayout.addStretch()
buttonLayout.addWidget(self.undoButton)
buttonLayout.addWidget(self.redoButton)
buttonLayout.addStretch()
buttonLayout.addWidget(self.quitButton)
return buttonLayout
def createModel(self):
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Titles', 'Summaries'])
rootItem = model.invisibleRootItem()
#First top-level row and children
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0')]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00')]
item01 = [QtGui.QStandardItem('Title01'), QtGui.QStandardItem('Summary01')]
rootItem.appendRow(item0)
item0[0].appendRow(item00)
item0[0].appendRow(item01)
#Second top-level item and its children
item1 = [QtGui.QStandardItem('Title1'), QtGui.QStandardItem('Summary1')]
item10 = [QtGui.QStandardItem('Title10'), QtGui.QStandardItem('Summary10')]
item11 = [QtGui.QStandardItem('Title11'), QtGui.QStandardItem('Summary11')]
rootItem.appendRow(item1)
item1[0].appendRow(item10)
item1[0].appendRow(item11)
return model
def main():
app = QtGui.QApplication(sys.argv)
newTree = UndoableTree()
newTree.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
See Question&Answers more detail:os