拖放而没有重复的元素

时间:2018-07-30 16:49:34

标签: python python-3.x drag-and-drop pyqt pyqt4

在带有Python 3的PyQt4中,如何访问拖放到视图/模型中的数据?

背景

我正在用两个QListView建立一个接口。我希望能够从第一个视图中拖放一个项目到第二个视图中。但是,列表需要保持唯一性,因此删除列表中已经存在的项目应该无济于事。

问题

我无法弄清楚如何访问要删除的数据以验证其是否不在列表中。

研究

我找到了QAbstractItemModel方法dropMimeData(),该方法应返回True接受删除的数据,并返回False拒绝它。但是,拖放数据位于QMimeData中,并且类型为application/x-qabstractitemmodeldatalist。从the docs开始,我尝试对数据进行解码:

def dropMimeData(self, data, action, row, column, parent=None):
    stream = QtCore.QDataStream(data.data('application/x-qabstractitemmodeldatalist'))
    text = ''
    while not stream.atEnd():
        stream >> text
        print(text)

但是,如果我运行此命令,我会得到

    stream >> text
ValueError: string of length 1 expected

如果我设置了text = 'a',那么a只会被重复打印。

我尝试了this solution,但是在Python 3中,我无法创建QVariant对象(每个this answer)。

问题

那么我如何访问PyQt中的拖放数据?有没有办法解码QMimeData东西?还是有其他方法可以检查掉了什么?

更新

这不是this question的重复项。我的问题是关于访问放置在QAbstractItemView / QAbstractItemModel中的数据,而那是关于在PyQt中进行基本的拖放。答案既没有解决如何从模仿类型'application/x-qabstractitemmodeldatalist'获取数据的问题,也没有说明如何防止在QAbstractItemModel中产生重复。

1 个答案:

答案 0 :(得分:0)

如果要控制拖放行为,则需要设置自己的mime数据。

您可以以任何方式对要拖放的数据进行编码。由于懒惰,我将把拖动的项目放到一个列表中并将其编码为JSON。

在源视图的模型中,覆盖mimeTypes()mimeData()

def mimeTypes(self):
    return ['text/json']

def mimeData(self, indexes):
    dragData = json.dumps([index.data() for index in indexes])
    mimeData = QtCore.QMimeData()
    mimeData.setData('text/json', dragData)
    return mimeData

当某人从列表中抓取并拖动一个/多个项目时,Qt将调用mimeData()对这些项目进行编码。在这里,我获取了拖动的每个索引的项目数据,将其放入列表中,通过JSON将列表转换为字符串,然后将该JSON添加到QMimeData

mimeTypes()中,我指定了哑剧数据将包括JSON数据。


在目标视图的模型中,覆盖dropMimeData()

def dropMimeData(self, data, action, row, column, parent=None):
    dropData = json.loads(bytes(data.data('text/json')))
    for item in dropData:
        if item in self.stringList():
            self.removeRow(self.stringList().index(item))
    if row != -1:
        beginRow = row
    elif parent:
        beginRow = parent.row()
    else:
        beginRow = self.rowCount()
    self.insertRows(beginRow, len(dropData))
    for i, item in enumerate(dropData):
        self.setData(self.index(beginRow+i, 0), item)
    return True

在第一行中,我从QMimeData中获取了JSON数据并对其进行了解码。然后,在for循环中,我检查一下目标视图中是否已经有一项。如果是这样,请将其删除。

之后,其余代码确定在哪里添加新行并将其插入。


更多信息是in the docs,尤其是有关adding new drag and drop types的部分。