我已经尝试在我的
Drag and Drop
中实现 QTreeView
已经好几个星期了。所以我决定创建这篇文章来寻找解决方案。我查了很多网站,Qt的官网,github上都查不到。我还尝试询问 chatGPT 是否可以向我展示在 QTreeView
中拖放的示例,但我也没有成功。所以这就是我想要实现的目标:我想从 QTreeView
类创建一个 QAbstractItemModel
。然后我希望能够重新排序我的项目,例如将最后一个项目移动到第二行,或者将其移动到其他项目上以便将其作为该项目的子项插入。如果我也能移动一个孩子来制作顶级物品,那就太好了。顺便说一句,我正在使用 PySide6 所以问题可能来自模块?
这是一段需要处理的代码,它已经有一个带有子项的模型,因此您可以测试其中的每个方法并添加实现拖放所需的方法:
import sys
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self, parent: QWidget = None):
super().__init__(parent)
self.resize(573, 468)
self.frame = QFrame()
self.setCentralWidget(self.frame)
self.hlayout = QHBoxLayout()
self.frame.setLayout(self.hlayout)
self.view = QTreeView()
self.view.setAlternatingRowColors(True)
self.view.setSelectionBehavior(QAbstractItemView.SelectItems)
self.view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
self.view.setAnimated(False)
self.view.setAllColumnsShowFocus(True)
self.hlayout.addWidget(self.view)
headers = ["value",'Type','Progress Bar','Test','Test','Test','Test']
self.model = TreeModel(headers, self)
# self.proxyModel = QSortFilterProxyModel(self)
# self.proxyModel.setSourceModel(self.model)
self.view.setModel(self.model)
self.view.expandAll()
for column in range(self.model.columnCount()):
self.view.resizeColumnToContents(column)
class TreeItem:
def __init__(self, data: list, parent: 'TreeItem' = None):
self.item_data = data
self.parent_item = parent
self.child_items = []
def child(self, number: int) -> 'TreeItem':
if number < 0 or number >= len(self.child_items):
return None
return self.child_items[number]
def last_child(self):
return self.child_items[-1] if self.child_items else None
def child_count(self) -> int:
return len(self.child_items)
def child_number(self) -> int:
if self.parent_item:
return self.parent_item.child_items.index(self)
return 0
def column_count(self) -> int:
return len(self.item_data)
def data(self, column: int):
if column < 0 or column >= len(self.item_data):
return None
return self.item_data[column]
def insert_children(self, position: int, count: int, columns: int) -> bool:
if position < 0 or position > len(self.child_items):
return False
for row in range(count):
data = [None] * columns
item = TreeItem(data.copy(), self)
self.child_items.insert(position, item)
return True
def remove_children(self, position: int, count: int) -> bool:
if position < 0 or position + count > len(self.child_items):
return False
for row in range(count):
self.child_items.pop(position)
return True
def parent(self):
return self.parent_item
def set_data(self, column: int, value):
if column < 0 or column >= len(self.item_data):
return False
self.item_data[column] = value
return True
def __repr__(self) -> str:
result = f"<treeitem.TreeItem at 0x{id(self):x}"
for d in self.item_data:
result += f' "{d}"' if d else " <None>"
result += f", {len(self.child_items)} children>"
return result
class TreeModel(QAbstractItemModel):
def __init__(self, headers: list, parent=None):
super().__init__(parent)
self.root_data = headers
self.root_item = TreeItem(self.root_data.copy())
self.setup_model_data(self.root_item)
def columnCount(self, parent: QModelIndex = None) -> int:
return self.root_item.column_count()
def data(self, index: QModelIndex, role: int = None):
if not index.isValid():
return None
if role != Qt.DisplayRole and role != Qt.EditRole:
return None
item: TreeItem = self.get_item(index)
return item.data(index.column())
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
if not index.isValid():
return Qt.NoItemFlags
return Qt.ItemIsEditable | QAbstractItemModel.flags(self, index)
def get_item(self, index: QModelIndex = QModelIndex()) -> TreeItem:
if index.isValid():
item: TreeItem = index.internalPointer()
if item:
return item
return self.root_item
def headerData(self, section: int, orientation: Qt.Orientation,
role: int = Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.root_item.data(section)
return None
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
if parent.isValid() and parent.column() != 0:
return QModelIndex()
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return QModelIndex()
child_item: TreeItem = parent_item.child(row)
if child_item:
return self.createIndex(row, column, child_item)
return QModelIndex()
def insertColumns(self, position: int, columns: int,
parent: QModelIndex = QModelIndex()) -> bool:
self.beginInsertColumns(parent, position, position + columns - 1)
success: bool = self.root_item.insert_columns(position, columns)
self.endInsertColumns()
return success
def insertRows(self, position: int, rows: int,
parent: QModelIndex = QModelIndex()) -> bool:
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return False
self.beginInsertRows(parent, position, position + rows - 1)
column_count = self.root_item.column_count()
success: bool = parent_item.insert_children(position, rows, column_count)
self.endInsertRows()
return success
def parent(self, index: QModelIndex = QModelIndex()) -> QModelIndex:
if not index.isValid():
return QModelIndex()
child_item: TreeItem = self.get_item(index)
if child_item:
parent_item: TreeItem = child_item.parent()
else:
parent_item = None
if parent_item == self.root_item or not parent_item:
return QModelIndex()
return self.createIndex(parent_item.child_number(), 0, parent_item)
def removeColumns(self, position: int, columns: int,
parent: QModelIndex = QModelIndex()) -> bool:
self.beginRemoveColumns(parent, position, position + columns - 1)
success: bool = self.root_item.remove_columns(position, columns)
self.endRemoveColumns()
if self.root_item.column_count() == 0:
self.removeRows(0, self.rowCount())
return success
def removeRows(self, position: int, rows: int,
parent: QModelIndex = QModelIndex()) -> bool:
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return False
self.beginRemoveRows(parent, position, position + rows - 1)
success: bool = parent_item.remove_children(position, rows)
self.endRemoveRows()
return success
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
if parent.isValid() and parent.column() > 0:
return 0
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return 0
return parent_item.child_count()
def setData(self, index: QModelIndex, value, role: int) -> bool:
if role != Qt.EditRole:
return False
item: TreeItem = self.get_item(index)
result: bool = item.set_data(index.column(), value)
if result:
self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])
return result
def setHeaderData(self, section: int, orientation: Qt.Orientation, value,
role: int = None) -> bool:
if role != Qt.EditRole or orientation != Qt.Horizontal:
return False
result: bool = self.root_item.set_data(section, value)
if result:
self.headerDataChanged.emit(orientation, section, section)
return result
def setup_model_data(self, parent: TreeItem):
parents = [parent]
Data = [["Test 1",'diam',10,2,3,4,5,6],["Test 2",'len',55,2,3,4,5,6],["Test 3",'conc',64,2,3,4,5,6],["Test 4",'diam',9,2,3,4,5,6],["Test 5",'len',12,2,3,4,5,6]]
for item in Data :
parent : TreeItem = parents[0]
col_count = self.root_item.column_count()
parent.insert_children(parent.child_count(), 1, col_count)
column_data = [item[0],item[1],item[2],item[3],item[4],item[5],item[6]]
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
parent2 : TreeItem = parent.last_child()
parent2.insert_children(parent2.child_count(), 1, col_count)
column_data = [item[0],item[1],item[2],item[3],item[4],item[5],item[6]]
for column in range(len(column_data)):
child = parent2.last_child()
child.set_data(column, column_data[column])
if __name__=="__main__" :
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
我的每次尝试都崩溃了,每次都有不同的错误消息。大多数时候,我只能将物品放在其他物品上,但我永远不能将它们插入到其他物品中间。所以我认为从头开始是理解它如何工作以及如何正确实现它的最佳解决方案。我真的希望有人能找到答案,感谢您花时间阅读这篇文章。