PySide:如何将QTreeView(QStandardItemModel)项拖拽至QLineEdit并获取数据
将QTreeView项拖拽到QLineEdit的实现方案
我来帮你搞定这个拖拽问题!其实核心就是处理好拖拽时的MIME数据传递,下面给你一个完整的可运行示例,每一步都讲清楚:
关键思路
- 让QTreeView允许向外拖拽项
- 让QLineEdit接受拖拽事件
- 正确解析拖拽过来的MIME数据,提取项的文本内容
完整代码示例
from PySide6.QtWidgets import (QApplication, QTreeView, QLineEdit, QWidget, QVBoxLayout, QStandardItem, QStandardItemModel) from PySide6.QtCore import (Qt, QMimeData, QModelIndex, QDataStream, QIODevice) # 自定义模型,添加纯文本格式的MIME数据(可选但更简单) class CustomStandardItemModel(QStandardItemModel): def mimeData(self, indexes): # 先获取父类默认的MIME数据 mime_data = super().mimeData(indexes) # 如果有选中的项,添加纯文本格式的数据 if indexes: first_item_text = self.data(indexes[0], Qt.DisplayRole) mime_data.setText(first_item_text) return mime_data # 自定义TreeView,开启拖拽功能 class MyTreeView(QTreeView): def __init__(self, parent=None): super().__init__(parent) # 设置为仅允许向外拖拽 self.setDragMode(QTreeView.DragOnly) # 初始化示例数据 model = CustomStandardItemModel() root = model.invisibleRootItem() # 添加一些测试项 item1 = QStandardItem("项目A") subitem1 = QStandardItem("子项目A1") item1.appendRow(subitem1) item2 = QStandardItem("项目B") root.appendRows([item1, item2]) self.setModel(model) self.expandAll() # 展开所有节点方便拖拽 # 自定义LineEdit,处理拖拽接收 class MyLineEdit(QLineEdit): def __init__(self, parent=None): super().__init__(parent) # 开启接受拖拽的功能 self.setAcceptDrops(True) self.setPlaceholderText("拖拽树中的项到这里...") def dragEnterEvent(self, event): # 检查MIME数据是否符合要求(纯文本或模型数据格式) if event.mimeData().hasText() or event.mimeData().hasFormat("application/x-qabstractitemmodeldatalist"): event.acceptProposedAction() else: super().dragEnterEvent(event) def dragMoveEvent(self, event): # 同dragEnterEvent的检查逻辑 if event.mimeData().hasText() or event.mimeData().hasFormat("application/x-qabstractitemmodeldatalist"): event.acceptProposedAction() else: super().dragMoveEvent(event) def dropEvent(self, event): # 优先使用纯文本格式(如果有的话) if event.mimeData().hasText(): self.setText(event.mimeData().text()) event.acceptProposedAction() # 如果只有模型默认的MIME格式,就解析它 elif event.mimeData().hasFormat("application/x-qabstractitemmodeldatalist"): data_stream = QDataStream(event.mimeData().data("application/x-qabstractitemmodeldatalist"), QIODevice.ReadOnly) # 模型MIME数据的格式是:每行/列对应一个QMap<角色, 值> while not data_stream.atEnd(): # 读取无关的行列信息,重点是后面的角色数据 data_stream.readInt32() # row data_stream.readInt32() # column map_size = data_stream.readInt32() item_data = {} for _ in range(map_size): role = data_stream.readInt32() value = data_stream.readQVariant() item_data[role] = value # 提取显示文本 if Qt.DisplayRole in item_data: self.setText(item_data[Qt.DisplayRole]) break event.acceptProposedAction() else: super().dropEvent(event) # 主窗口测试 class MainWindow(QWidget): def __init__(self): super().__init__() layout = QVBoxLayout() layout.addWidget(MyTreeView()) layout.addWidget(MyLineEdit()) self.setLayout(layout) self.setWindowTitle("TreeView拖拽到LineEdit演示") self.resize(400, 350) if __name__ == "__main__": app = QApplication([]) window = MainWindow() window.show() app.exec()
代码说明
- CustomStandardItemModel:我重写了
mimeData方法,在默认的模型MIME数据基础上添加了纯文本格式,这样LineEdit可以直接读取文本,不用复杂解析。如果不想自定义模型,也可以直接用默认的QStandardItemModel,此时LineEdit会走解析模型MIME数据的分支。 - MyTreeView:通过
setDragMode(QTreeView.DragOnly)开启向外拖拽功能,并初始化了一些测试数据方便你验证。 - MyLineEdit:
- 开启
setAcceptDrops(True)允许接收拖拽 dragEnterEvent和dragMoveEvent用来筛选可接受的拖拽类型dropEvent是核心:先尝试读取纯文本,不行就解析模型的MIME数据,提取出项的显示文本并设置到LineEdit中
- 开启
这样你就能轻松实现从TreeView拖拽项到LineEdit的功能啦!
内容的提问来源于stack exchange,提问作者stowaway
相关产品推荐
相关产品推荐

