2015-06-27 60 views
0

我想在用户按下按钮时将节点向上移动到其父节点中。我拍了一张儿童快照,重新排列他们,然后将他们全部加回去。然而,最初选择的节点永远不会被takeChild()方法移除,所以我最终得到了父节点中的3个节点,而不是两个节点。试试下面的例子,选择Type B节点,然后选择'move node up'按钮。基本的树代码是从另一个这样的QQ和引用波纹管。在PyQt中移动节点位置QTreeWidget

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_()) 

回答

1

出现此问题,因为一旦你已删除了与(在第一次循环parent.takechild(j))指数为0的项目,那么剩下的唯一的项目目前正处于指数​​为0,但下一次迭代尝试与删除子项索引1,现在不存在!

简而言之,当您修改树视图(在这种情况下通过删除一个项目),您用来跟踪树视图中位置的任何索引都变得毫无意义。

您可以通过parent.takeChildren()一次性删除所有项目或通过for j in range(parent.childCount()-1,-1,-1)向后遍历列表来解决您的特定问题。

请注意,在使用treeview做其他事情时,应该牢记这类问题。您必须仔细考虑如何更改树视图会影响您用来访问树视图的任何整数!