在实现通用拖放模型时,我遇到了以下问题。在对mimeData进行编码时,我想将拖动索引的原始行和列写入数据流。项目数据的序列化取决于程序员选择的特定数据结构,因此应该封装在单独的方法中。DragDropListModel 的子类对其模型项使用不同的数据结构只需覆盖此封装方法。
问题是 QDataStream 上的读/写是有状态的。例如,请看一下 decode_data()。将 QDataStream 对象传递给负责从流中解码下一项的方法,(可能)调用复制构造函数。现在 decode_item_from_stream() 使用数据流的副本。在反序列化过程中完成的读取改变了复制的数据流对象的状态,但 decode_data() 中原始对象的状态保持不变。这应该会导致 while 循环的下一次迭代崩溃。
因此我的两个问题是:
我的描述是准确的还是我误解了什么?
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