我在QTreeWidget中覆盖了dragMoveEvent
和dropEvent
方法,我只有正确的second layer
效果,它可以互相拖动,防止进入对方。但是first and third levels
有不同的错误。例如,节点1-1-1和节点1-2-2不能相互拖动。Node1可以拖动到Node2中,这不符合我完成的要求。
class TreeWidget(QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if current_item and current_item.type() == 0:
super().dragMoveEvent(event)
elif item and item.type() == 1 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
elif item and item.type() == 2 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if current_item and current_item.type() == 0:
super(TreeWidget, self).dropEvent(event)
elif item and item.type() == 1 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
elif item and item.type() == 2 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
else:
event.ignore()
class BasicTreeTest1(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTreeWidget')
self.tree = TreeWidget()
root1 = QTreeWidgetItem(self.tree,type=0)
root1.setText(0, 'node1')
child1_1 = QTreeWidgetItem(root1,type=1)
child1_1.setText(0, 'node1-1')
child1_1.setFlags(child1_1.flags() & ~Qt.ItemIsDropEnabled)
child1_2 = QTreeWidgetItem(root1, type=1)
child1_2.setText(0, 'node1-2')
child1_2.setFlags(child1_2.flags() & ~Qt.ItemIsDropEnabled)
child1_1_1 = QTreeWidgetItem(child1_1, type=2)
child1_1_1.setText(0, 'node1-1-1')
child1_1_1.setFlags(child1_1_1.flags() & ~Qt.ItemIsDropEnabled)
child1_2_1 = QTreeWidgetItem(child1_1, type=2)
child1_2_1.setText(0, 'node1-2-1')
child1_2_1.setFlags(child1_2_1.flags() & ~Qt.ItemIsDropEnabled)
root2 = QTreeWidgetItem(self.tree,type=0)
root2.setText(0, 'node2')
child2_1 = QTreeWidgetItem(root2, type=1)
child2_1.setText(0, 'node2-1')
child2_1.setFlags(child2_1.flags() & ~Qt.ItemIsDropEnabled)
child2_2 = QTreeWidgetItem(root2, type=1)
child2_2.setText(0, 'node2-2')
child2_2.setFlags(child2_2.flags() & ~Qt.ItemIsDropEnabled)
root3 = QTreeWidgetItem(self.tree, type=0)
root3.setText(0, 'node3')
child3_1 = QTreeWidgetItem(root3, type=1)
child3_1.setText(0, 'node3_1')
child3_1.setFlags(child3_1.flags() & ~Qt.ItemIsDropEnabled)
child3_2 = QTreeWidgetItem(root3, type=1)
child3_2.setText(0, 'node3_2')
child3_2.setFlags(child3_2.flags() & ~Qt.ItemIsDropEnabled)
child3_2_1 = QTreeWidgetItem(child3_2, type=2)
child3_2_1.setText(0, 'node3-2-1')
child3_2_1.setFlags(child3_2_1.flags() & ~Qt.ItemIsDropEnabled)
child3_2_2 = QTreeWidgetItem(child3_2, type=2)
child3_2_2.setText(0, 'node3-2-2')
child3_2_2.setFlags(child3_2_2.flags() & ~Qt.ItemIsDropEnabled)
# root1.setFlags(root1.flags() & ~Qt.ItemIsDropEnabled)
# root2.setFlags(root2.flags() & ~Qt.ItemIsDropEnabled)
# root3.setFlags(root3.flags() & ~Qt.ItemIsDropEnabled)
# child22.setFlags(child22.flags() & ~Qt.ItemIsDropEnabled)
self.setCentralWidget(self.tree)
self.tree.expandAll()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = BasicTreeTest1()
w.show()
sys.exit(app.exec_())
这个网站是我的参考:id/文章/详细信息/125258736
发布于 2022-07-17 12:19:41
更新
由于您的最新编辑更改了需求,因此需要一种不同的方法。目前,我唯一能看到的解决方案是得到当前的跌落指示器,这样就有可能知道目标是否在某一项之上或下方。Qt为此使用了一个私有方法,必须将其移植到PyQt以访问相同的功能。我已经在下面的演示脚本中实现了这一点,它只允许在自己的父级内重新排序兄弟项目(在任何级别):
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class TreeWidget(QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
if self.canDrop(event):
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
if self.canDrop(event):
super().dropEvent(event)
else:
event.ignore()
def canDrop(self, event):
target = self.itemAt(event.pos())
current = self.currentItem()
if target is not None and target.parent() is current.parent():
index = self.indexFromItem(target)
indicator = self.dragIndicator(
event.pos(), self.visualItemRect(target), index)
return (indicator == QAbstractItemView.AboveItem or
indicator == QAbstractItemView.BelowItem)
return False
def dragIndicator(self, pos, rect, index):
indicator = QAbstractItemView.OnViewport
if not self.dragDropOverwriteMode():
margin = int(max(2, min(rect.height() / 5.5, 12)))
if pos.y() - rect.top() < margin:
indicator = QAbstractItemView.AboveItem
elif rect.bottom() - pos.y() < margin:
indicator = QAbstractItemView.BelowItem
elif rect.contains(pos, True):
indicator = QAbstractItemView.OnItem
else:
touching = rect.adjust(-1, -1, 1, 1)
if touching.contains(pos, False):
indicator = QAbstractItemView.OnItem
if (indicator == QAbstractItemView.OnItem and
not self.model().flags(index) & Qt.ItemIsDropEnabled):
if pos.y() < rect.center().y():
indicator = QAbstractItemView.AboveItem
else:
indicator = QAbstractItemView.BelowItem
return indicator
class BasicTreeTest1(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTreeWidget')
self.tree = TreeWidget()
root1 = QTreeWidgetItem(self.tree,type=0)
root1.setText(0, 'node1')
child1_1 = QTreeWidgetItem(root1,type=1)
child1_1.setText(0, 'node1-1')
child1_2 = QTreeWidgetItem(root1, type=1)
child1_2.setText(0, 'node1-2')
child1_1_1 = QTreeWidgetItem(child1_1, type=2)
child1_1_1.setText(0, 'node1-1-1')
child1_2_1 = QTreeWidgetItem(child1_1, type=2)
child1_2_1.setText(0, 'node1-2-1')
root2 = QTreeWidgetItem(self.tree,type=0)
root2.setText(0, 'node2')
child2_1 = QTreeWidgetItem(root2, type=1)
child2_1.setText(0, 'node2-1')
child2_2 = QTreeWidgetItem(root2, type=1)
child2_2.setText(0, 'node2-2')
root3 = QTreeWidgetItem(self.tree, type=0)
root3.setText(0, 'node3')
child3_1 = QTreeWidgetItem(root3, type=1)
child3_1.setText(0, 'node3_1')
child3_2 = QTreeWidgetItem(root3, type=1)
child3_2.setText(0, 'node3_2')
child3_2_1 = QTreeWidgetItem(child3_2, type=2)
child3_2_1.setText(0, 'node3-2-1')
child3_2_2 = QTreeWidgetItem(child3_2, type=2)
child3_2_2.setText(0, 'node3-2-2')
self.setCentralWidget(self.tree)
self.tree.expandAll()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = BasicTreeTest1()
w.setGeometry(600, 100, 500, 400)
w.show()
sys.exit(app.exec_())
前解
若要防止子项目彼此掉落,您可以使用更改其项目标志。默认标志包括Qt.ItemIsDropEnabled
,因此只需删除:
child111 = QTreeWidgetItem(root1, type=1)
child111.setFlags(child111.flags() & ~Qt.ItemIsDropEnabled)
当然,这不会阻止父母之间拖放项目,但是通过重新实现dragMoveEvent
和dropEvent
,您的当前代码已经阻止了这一点,因此看起来上面的更改就足够了。
下面是一个基于代码的完整的工作示例:
from PyQt5 import QtCore, QtWidgets
class TreeWidget(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QtWidgets.QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if item and item.type() == 1 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if item and item.type() == 1 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
else:
event.ignore()
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.tree = TreeWidget()
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tree)
root1 = QtWidgets.QTreeWidgetItem(self.tree,type=0)
root1.setText(0, '1')
child111 = QtWidgets.QTreeWidgetItem(root1,type=1)
child111.setFlags(child111.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child111.setText(0, '11')
child12 = QtWidgets.QTreeWidgetItem(root1, type=1)
child12.setFlags(child12.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child12.setText(0, '12')
root2 = QtWidgets.QTreeWidgetItem(self.tree,type=0)
root2.setText(0, '2')
child121 = QtWidgets.QTreeWidgetItem(root2, type=1)
child121.setFlags(child121.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child121.setText(0, '21')
child122 = QtWidgets.QTreeWidgetItem(root2, type=1)
child122.setFlags(child122.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child122.setText(0, '22')
self.tree.expandAll()
if __name__ == '__main__':
app = QtWidgets.QApplication(['Test'])
window = Window()
window.setWindowTitle('Test')
window.setGeometry(600, 100, 300, 200)
window.show()
app.exec_()
https://stackoverflow.com/questions/72978651
复制相似问题