【问题标题】:Implementation of clone in QStandardItem subclassQStandardItem 子类中克隆的实现
【发布时间】:2020-07-01 11:48:38
【问题描述】:

我使用 QStandardItemModel 和 QTreeView 来显示自定义项目。这些项目分为三种不同的类型 FILTER_TYPE、MODIFIER_TYPE 和 GROUP_TYPE。

我希望能够使用视图中的拖放 (InternalMove) 对模型中的项目进行重新排序。如果我理解正确,我必须在我的模型上使用 setItemPrototype(MyItem()) 以便它在移动项目时使用自定义的 MyItem 而不是一般的 QStandardItem。

我的理解是创建自定义 MyItem 的新实例,然后将旧项目的所有数据和标志复制到新项目。但是,模型似乎只初始化了一个新的 MyItem 而从不复制数据。

因此:如何在 MyItem 子类中重新实现 QStandardItem.clone() 以将所有数据和标志复制到新项目中?我是否必须手动检查所有自定义数据角色并将其值分配给新项目?

Item 类如下所示:

class MyItem(QtGui.QStandardItem):
    FILTER_TYPE = QtGui.QStandardItem.UserType + 1
    MODIFIER_TYPE = QtGui.QStandardItem.UserType + 2
    GROUP_TYPE = QtGui.QStandardItem.UserType + 3

    TYPE = QtCore.Qt.UserRole + 0
    NAME = QtCore.Qt.UserRole + 1 
  
    IS_PROCESSED = QtCore.Qt.UserRole + 5
    OUTPUT = QtCore.Qt.UserRole + 6

    FN = QtCore.Qt.UserRole + 7
    DEFAULT_PARAMS = QtCore.Qt.UserRole + 8
    PARAMETER_SET = QtCore.Qt.UserRole + 9

    def __init__(self):
        super().__init__()

        self.name = ""
        self.full_name = ""
        self.description = ""

        self.fn = None
        self.default_params = None
        self.parameter_set = None

        self.is_active = True
        self.is_processed = False
        self.output = None

        self.icon = QtGui.QIcon()

    def clone(self):
        item = Item() 
        
        ??? WHAT GOES HERE TO COPY ALL DATA AND FLAGS ???
            
        return item

    def __setattr__(self, name, value):
        if name == 'name':
            self.setData(value, self.NAME)
        elif name == 'full_name':
            self.setData(value, QtCore.Qt.DisplayRole)
            self.setData(value, QtCore.Qt.EditRole)
        elif name == 'description':
            self.setData(value, QtCore.Qt.ToolTipRole)
        
        ...

        else:
            super().__setattr__(name, value)

    def __getattribute__(self, name):
        if name == 'name':
            return self.data(self.NAME)
        elif name == 'full_name':
            return self.data(QtCore.Qt.DisplayRole)
        elif name == 'description':
            return self.data(QtCore.Qt.ToolTipRole)

        ...

        else:
            return super().__getattribute__(name)

    def initializeItem(self, type_, name, full_name, description="", fn=None, default_params=None):
        
        self.name = name
        self.full_name = full_name
        self.description = description
        
        self.fn = fn
        self.default_params = default_params
        self.parameter_set = ParameterSet(params_list=default_params)

        self.setData(type_, self.TYPE)
        
        flags = QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled
        if type_ == self.FILTER_TYPE:
            self.icon = QtGui.QIcon('resources/filter.png')
            flags = flags|QtCore.Qt.ItemNeverHasChildren
        elif type_ == self.MODIFIER_TYPE:
            self.icon = QtGui.QIcon('resources/modifier.png')
            flags = flags|QtCore.Qt.ItemIsDropEnabled
        elif type_ == self.GROUP_TYPE:
            self.icon = QtGui.QIcon('resources/folder.png')
            flags = flags|QtCore.Qt.ItemIsDropEnabled|QtCore.Qt.ItemIsEditable
        self.setFlags(flags)

    def type(self):
        return self.data(self.TYPE)

      

模型实现如下所示:

from tree.items import MyItem


class TreeModel(QtGui.QStandardItemModel):
    
    def __init__(self):
        super().__init__()

        self.setItemPrototype(MyItem())

【问题讨论】:

    标签: python pyqt pyqt5 qstandarditemmodel qstandarditem


    【解决方案1】:

    “克隆”的逻辑是创建一个具有与项目相同信息的对象,因此在这种情况下,您使用角色来存储该信息,因此您必须将所有信息复制到新项目中,在这种情况下你可以使用 QDataStream:

    def clone(self):
        item = MyItem()
        ba = QtCore.QByteArray()
        ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
        ds << self
        ds = QtCore.QDataStream(ba)
        ds >> item
        return item
    

    【讨论】:

    • 感谢您的回答!但是,这似乎仅在数据仅包含简单类型时才有效。然而,在我的例子中,包含多个输入元素的 QWidget 在项目数据中。在实施您的解决方案时,我收到错误 TypeError: cannot pickle 'QLineEdit' object。我认为解决此问题的唯一方法是在新项目上为所有正在使用的角色实际使用 setData()?
    • @Alex 正如克隆方法所指出的,您必须创建一个包含相同信息的项目,如果该项目存储一个小部件,那么很难复制它,因为它还涉及复制一个小部件很复杂(我会说不可能),因为要复制一个对象,您必须复制该对象的内部状态,并且在数值的情况下,复制数值就足够了(与字符串、QIcon 等相同)。 )
    • @Alex 但小部件不可复制,因为它们不会公开所有属性,即使它们具有相同的属性,也意味着具有相同的状态,因为变量的状态取决于那些属性 + 应用这些更改的时刻。
    • @Alex 您可以做的最近似的事情是不使用 QDataStream 并逐个复制属性,然后创建一个 QLineEdit ,在其中为您设置最重要的属性(可能只是文本),例如:item = MyItem()item.lineedit = QLineEdit()item.lineedit.setText(self.lineedit.text())
    • 所以在我需要的时候使用存储在项目中的简单类型重建 QWidget 会更好?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    相关资源
    最近更新 更多