Reputation: 9814
I am trying to move a node up within it's parent when user pushes a button. I take a snapshot of children, reorder them then add them all back. However the node initially selected is never removed by the takeChild() method, so I end up with 3 nodes in the parent instead of two. Try the example below by selecting the Type B node, then the 'move node up' button. The basic tree code was taken from another so qq and referenced bellow.
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
#see http://stackoverflow.com/questions/12737721/developing-pyqt4-tree-widget/13563375#13563375
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.treeWidget = QtGui.QTreeWidget()
self.treeWidget.setHeaderHidden(True)
self.addItems(self.treeWidget.invisibleRootItem())
self.treeWidget.itemChanged.connect (self.handleChanged)
layout = QtGui.QVBoxLayout()
layout.addWidget(self.treeWidget)
self.upPushButton = QtGui.QPushButton("Move node up")
layout.addWidget(self.upPushButton)
self.setLayout(layout)
self.connectSlot()
def addItems(self, parent):
column = 0
clients_item = self.addParent(parent, column, 'Clients', 'data Clients')
vendors_item = self.addParent(parent, column, 'Vendors', 'data Vendors')
time_period_item = self.addParent(parent, column, 'Time Period', 'data Time Period')
self.addChild(clients_item, column, 'Type A', 'data Type A')
self.addChild(clients_item, column, 'Type B', 'data Type B')
self.addChild(vendors_item, column, 'Mary', 'data Mary')
self.addChild(vendors_item, column, 'Arnold', 'data Arnold')
self.addChild(time_period_item, column, 'Init', 'data Init')
self.addChild(time_period_item, column, 'End', 'data End')
def addParent(self, parent, column, title, data):
item = QtGui.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setChildIndicatorPolicy(QtGui.QTreeWidgetItem.ShowIndicator)
item.setExpanded (True)
return item
def addChild(self, parent, column, title, data):
item = QtGui.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setCheckState (column, QtCore.Qt.Unchecked)
return item
def handleChanged(self, item, column):
if item.checkState(column) == QtCore.Qt.Checked:
print ("checked", item, item.text(column))
if item.checkState(column) == QtCore.Qt.Unchecked:
print ("unchecked", item, item.text(column))
def upPushButtonClicked(self):
'''Moves order within parent'''
selectedTreeItems = self.treeWidget.selectedItems()
if selectedTreeItems and len(selectedTreeItems) == 1:
item = selectedTreeItems[0]
itemData = item.data(0, Qt.UserRole)
parent = item.parent()
#get children
location = 0
siblings = []
if parent.childCount()>1:
for i in range(parent.childCount()):
sibling = parent.child(i)
if sibling == item:
location = i
siblings.append(sibling)
#switch position
a, b = siblings.index(parent.child(location-1)), siblings.index(parent.child(location))
siblings[b], siblings[a] = siblings[a], siblings[b]
#clear the branch
for j in range(parent.childCount()):
#This runs but the child is not removed when j == childCount-1
parent.takeChild(j)
#add all children back
for node in siblings:
self.addChild(parent, 0, node.text(0), node.data(0, Qt.UserRole))
def connectSlot(self):
self.upPushButton.clicked.connect(self.upPushButtonClicked)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Upvotes: 1
Views: 2341
Reputation: 11869
The problem occurs because once you have removed the item with index 0 (parent.takechild(j)
on the first iteration), then the only remaining item is now at index 0. But the next iteration tries to remove the child item with index 1, which doesn't exist now!
In short, when you modify the treeview (in this case by removing an item), any indexes you are using to keep track of a location in the treeview, become meaningless.
You can solve your specific problem by either removing all of the items at once with parent.takeChildren()
or iterate backwards through the list with for j in range(parent.childCount()-1,-1,-1)
.
Note that you should keep this sort of problem in mind when doing other things with the treeview. You must think carefully about how changing the treeview will affect any integers you are using to access the treeview!
Upvotes: 2