【发布时间】:2019-11-04 17:50:43
【问题描述】:
如以下代码所示,当您拖放一个项目(使用clone() 方法从QStandardItem 子类化)时,您会得到QStandardItem 而不是子类。此外 - 存储在类中或作为 setData 一部分的数据会丢失。我怀疑这是因为无法“序列化”数据。但我不知道如何“保存”数据 - 或元数据。如何保留QObject?下面的代码可以正常工作,但是一旦你移动了一个分支节点,分支和分支中的所有节点都会变成QStandardItem,而不是myItem,并且会丢失数据(如果有的话)。
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 4 09:10:16 2019
Test of Tree view with subclassed QStandardItem and Drag and Drop
enabled. When you move a parent the parent looses the subclass and thus
the meta - however, it also looses the data: This is likely because
the data cannot be serialized. How to fix?
@author: tcarnaha
"""
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
class myData():
def __init__(self, title):
self._title = title
self._stuff = dict()
self._obj = QtCore.QObject()
@property
def obj(self):
return self._obj
@obj.setter
def obj(self, value):
self._obj = value
@property
def title(self):
return self._title
@title.setter
def title(self, value):
self._title = value
class myItem(QtGui.QStandardItem):
def __init__(self, parent=None):
super(myItem, self).__init__(parent)
self._meta = None
@property
def meta(self):
return self._meta
@meta.setter
def meta(self, value):
self._meta = value
def clone(self):
print "My cloning"
old_data = self.data()
print "Old data [{}]".format(old_data)
old_meta = self.meta
obj = myItem()
obj.setData(old_data)
print "New data [{}]".format(obj.data())
obj.meta = old_meta
print "Clone is a ", obj.__class__
return obj
class mainWidget(QtWidgets.QMainWindow):
def __init__(self):
super(mainWidget, self).__init__()
self.model = QtGui.QStandardItemModel()
self.model.setItemPrototype(myItem())
self.view = QtWidgets.QTreeView()
self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.view.customContextMenuRequested.connect(self.list_click)
self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
self.view.setDefaultDropAction(QtCore.Qt.MoveAction)
self.view.setDragDropOverwriteMode(False)
self.view.setAcceptDrops(True)
self.view.setDropIndicatorShown(True)
self.view.setDragEnabled(True)
self.view.setModel(self.model)
dataA = myData('A thing')
parentA = myItem()
parentA.setText('A')
parentA.setDragEnabled(True)
parentA.setDropEnabled(True)
parentA.setData(dataA)
parentA.meta = QtCore.QObject()
childa = myItem()
childa.setText('a')
childb = myItem()
childb.setText('b')
childc = myItem()
childc.setText('c')
parentA.appendRows([childa, childb, childc])
dataB = myData('B thing')
parentB = myItem()
parentB.setText('B')
parentB.setDragEnabled(True)
parentB.setDropEnabled(True)
parentB.setData(dataB)
parentB.meta = QtCore.QObject()
childd = myItem()
childd.setText('d')
childe = myItem()
childe.setText('e')
childf = myItem()
childf.setText('f')
parentB.appendRows([childd, childe, childf])
self.model.appendRow(parentA)
self.model.appendRow(parentB)
classAct = QtWidgets.QAction('Class', self)
classAct.triggered.connect(self.classIs)
dataAct = QtWidgets.QAction('Data', self)
dataAct.triggered.connect(self.dataIs)
metaAct = QtWidgets.QAction('Meta', self)
metaAct.triggered.connect(self.metaIs)
self.menu = QtWidgets.QMenu("Item info")
self.menu.addAction(classAct)
self.menu.addAction(dataAct)
self.menu.addAction(metaAct)
self.setCentralWidget(self.view)
@QtCore.pyqtSlot(QtCore.QPoint)
def list_click(self, position):
self.menu.popup(self.view.viewport().mapToGlobal(position))
def classIs(self):
selected_indexes = self.view.selectedIndexes()
for index in selected_indexes:
item = self.model.itemFromIndex(index)
print "Item {} Class {} ".format(item.text(), item.__class__())
def dataIs(self):
selected_indexes = self.view.selectedIndexes()
for index in selected_indexes:
item = self.model.itemFromIndex(index)
try:
print "Item {} data {} Object {}".format(item.text(),
item.data().title,
item.data().obj)
except Exception as exc:
print "Data exception ", exc
def metaIs(self):
selected_indexes = self.view.selectedIndexes()
for index in selected_indexes:
item = self.model.itemFromIndex(index)
try:
print "Item {} meta {} ".format(item.text(), item.meta)
except Exception as exc:
print "Meta exception ", exc
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main = mainWidget()
main.show()
app.exec_()
【问题讨论】:
-
我认为您的意思是 obj = myItem() 而不是 obj = super()。很好 - 我明白 - 但是,无论“数据”和“元”是否丢失。如何避免?
-
好的,一旦你复制了正确的对象,那么只需将数据/元数据从主要对象复制到新对象——你当然会有手动进行——但应该是你的类的一部分——复制功能注意确保当你这样做时,你正在将苹果复制到苹果,有时你必须提取数据才能使用 setData 函数
-
在附加的代码中试图做到这一点 - 但它不起作用。在 clone 方法中保存数据(或元数据)不起作用:.data() 上出现以下错误:数据异常无法将 QVariant 转换回 Python 对象
-
查看您的 QStandardItem 对象文档,因为不,您不能按照您的方式进行操作 - 您使用
obj.data()获取数据,但您使用obj.setData(value[, role=Qt.UserRole + 1])设置数据,我相信这就是您的方式也设置元数据 - 如果不深入研究它就不能 100% 确定 - 你现在应该能够做到 -
这些都不起作用。我尝试使用 old_data = self.data() 获取数据(如果我使用 role=Qt.UserRole+1,它是隐含的并且不会改变行为)关键是在调用克隆之前数据(或元)丢失.尝试以类似方式保存元数据失败。
标签: python drag-and-drop pyqt5 qtreeview qstandarditemmodel