首页 > 解决方案 > 将 QDataStream 对象传递给另一个方法(复制构造函数与有状态)

问题描述

在实现通用拖放模型时,我遇到了以下问题。在对mimeData进行编码时,我想将拖动索引的原始行和列写入数据流。项目数据的序列化取决于程序员选择的特定数据结构,因此应该封装在单独的方法中。DragDropListModel 的子类对其模型项使用不同的数据结构只需覆盖此封装方法。

问题是 QDataStream 上的读/写是有状态的。例如,请看一下 decode_data()。将 QDataStream 对象传递给负责从流中解码下一项的方法,(可能)调用复制构造函数。现在 decode_item_from_stream() 使用数据流的副本。在反序列化过程中完成的读取改变了复制的数据流对象的状态,但 decode_data() 中原始对象的状态保持不变。这应该会导致 while 循环的下一次迭代崩溃。

因此我的两个问题是:

  1. 我的描述是准确的还是我误解了什么?

  2. python 是否有一种方法可以规避这些问题(其他语言可能通过引用传递来解决这个问题),同时保持方法彼此分开?

    class DragDropListModel(QtCore.QAbstractListModel):
        def __init__(self, tabText):
            super(DragDropListModel, self).__init__()
            self.model_data = []
    
        def data(self, index, role):
            item_data = self.model_data[index.row()]
    
            # DEBUG
            if role == QtCore.Qt.DisplayRole:
                return item_data[generic_tokens.Display]
            if role == QtCore.Qt.DecorationRole:
                return item_data[generic_tokens.Decoration]
            if role == QtCore.Qt.ToolTipRole:
                item_data[generic_tokens.ToolTip]
            if role == generic_roles.ItemDataRole:
                return item_data
    
        def rowCount(self, index):
            return len(self.model_data)
    
        def mimeTypes(self):
            """Returns the list of allowed MIME types"""
            return ["application/x-generic-drag-drop"]
    
        # Returns an object that contains serialized items of data corresponding to the list of indexes specified. 
        # The format used to describe the encoded data is obtained from the mimeTypes() function
        def mimeData(self, indexes:list):
            mimeData = QtCore.QMimeData()
            encodedData = self.encode_data(indexes)
            mimeData.setData("application/x-generic-drag-drop", encodedData)
            return mimeData
    
        def encode_data(self, indexes:list):
            byteArray = QtCore.QByteArray()
            dataStream = QtCore.QDataStream(byteArray, QtCore.QIODevice.WriteOnly)
            # implement writing to datastream 
            for i, index in enumerate(indexes):
                # encode index
                dataStream.writeInt16(index.row())
                dataStream.writeInt16(index.column())
                # encode item
                dataStream = self.encode_item_to_stream(
                    item=index.data(generic_roles.ItemDataRole)
                    stream = dataStream
                )
    
            return byteArray
    
        def encode_item_to_stream(self, item, stream:QtCore.QDataStream) -> QtCore.QDataStream:
            """can be overridden by subclasses of the generic drag drop model to allow for custom item serialization"""
            pass
    
        def decode_data(self, data:QtCore.QMimeData)-> list: 
            # decoding the dropped data
            encodedData = data.data("application/x-generic-drag-drop")
            stream = QtCore.QDataStream(encodedData, QtCore.QIODevice.ReadOnly)
    
            source_indexes = []
            decoded_items = []
            while not stream.atEnd():
                # decode index
                row = stream.readInt16()
                col = stream.readInt16()
                source_indexes.append((row, col))
                # decode item
                decoded_items.append(stream)
    
            return indexes, decoded_items
    
        def decode_item_from_stream(self, stream:QtCore.QDataStream):
            """can be overridden by subclasses of the generic drag drop model to allow for custom item serialization"""
            pass
    

标签: pythonpyqt5pyside2qabstractlistmodelqdatastream

解决方案


推荐阅读