在 PyQt QTreeWidget 中移动节点位置
Move node position in PyQt QTreeWidget
我正在尝试在用户按下按钮时在 parent 中向上移动一个节点。我拍摄了 children 的快照,重新排序然后将它们全部添加回来。但是,最初选择的节点永远不会被 takeChild() 方法删除,所以我最终在 parent 中得到了 3 个节点,而不是两个。通过选择 Type B 节点,然后选择 'move node up' 按钮来尝试下面的示例。基本的树代码取自另一个so qq,并在下面引用。
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
#see
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_())
出现问题是因为一旦您删除了索引为 0 的项目(在第一次迭代中为 parent.takechild(j)
),那么唯一剩下的项目现在位于索引 0。但是下一次迭代会尝试删除子项索引为 1 的项目,现在不存在!
简而言之,当您修改树视图(在本例中是通过删除项目)时,您用于跟踪树视图中某个位置的任何索引都变得毫无意义。
您可以通过使用 parent.takeChildren()
一次删除所有项目或使用 for j in range(parent.childCount()-1,-1,-1)
.
向后遍历列表来解决您的特定问题
请注意,在使用树视图进行其他操作时,应牢记此类问题。您必须仔细考虑更改树视图将如何影响您用于访问树视图的任何整数!
我正在尝试在用户按下按钮时在 parent 中向上移动一个节点。我拍摄了 children 的快照,重新排序然后将它们全部添加回来。但是,最初选择的节点永远不会被 takeChild() 方法删除,所以我最终在 parent 中得到了 3 个节点,而不是两个。通过选择 Type B 节点,然后选择 'move node up' 按钮来尝试下面的示例。基本的树代码取自另一个so qq,并在下面引用。
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
#see
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_())
出现问题是因为一旦您删除了索引为 0 的项目(在第一次迭代中为 parent.takechild(j)
),那么唯一剩下的项目现在位于索引 0。但是下一次迭代会尝试删除子项索引为 1 的项目,现在不存在!
简而言之,当您修改树视图(在本例中是通过删除项目)时,您用于跟踪树视图中某个位置的任何索引都变得毫无意义。
您可以通过使用 parent.takeChildren()
一次删除所有项目或使用 for j in range(parent.childCount()-1,-1,-1)
.
请注意,在使用树视图进行其他操作时,应牢记此类问题。您必须仔细考虑更改树视图将如何影响您用于访问树视图的任何整数!