[QStandardItem在移动项目时无法正确克隆

问题描述 投票:0回答:1

如下面的代码所示,当拖放一个项目(使用.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()
        old_meta = self.meta
        obj = super(myItem, self).clone()
        obj.setData(old_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_()
python drag-and-drop pyqt5 qtreeview qstandarditemmodel
1个回答
0
投票

您不是要克隆课程,而是普通的QStandardItem

obj = super(myItem, self).clone()

这实际上意味着“调用base类的clone()方法”。当从单个类进行子类化时,super()的行为就像调用以子类实例作为第一个参数的类方法一样,因此在这种情况下,这样做确实很简单:

obj = QtGui.QStandardItem.clone(self)

super()最常见的优点是简单性和可维护性(如果更改基类,将要继承,则只需在子类声明中进行操作即可);除此之外,它最重要的好处来自多重继承,即当您从多个]基类继承时,但是由于在PyQt中这种情况很少见,因此并非如此。同样,一个以上的Qt类不可能实现多重继承。

[在setItemPrototype()(强调我的)中指定:

提供您自己的原型,子类QStandardItem,重新实现QStandardItem :: clone()并将原型设置为您的实例自定义类

实际上setItemPrototype()实际上是clone()是使用does构造函数,该构造函数创建other

项目的copy

因此,只需执行以下操作即可获得正确的克隆:

QStandardItem(other)
© www.soinside.com 2019 - 2024. All rights reserved.