【问题标题】:Drag and Drop without duplicate elements拖放没有重复的元素
【发布时间】:2018-07-30 16:49:33
【问题描述】:

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

背景

我正在用两个QListViews 构建一个接口。我希望能够从第一个视图中拖动一个项目并将其放到第二个视图中。但是,列表需要保持唯一性,因此删除列表中已经存在的项目应该什么都不做。

问题

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

研究

我找到了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 中的基本拖放。答案没有说明如何从 mimetype 'application/x-qabstractitemmodeldatalist' 获取数据,也没有说明如何防止 QAbstractItemModel 中的重复。

【问题讨论】:

  • 为了理解你,你有2个QListView,假设我从第一个拖到第二个,我的问题是从第一个QListView中删除的拖拽项目?
  • @eyllanesc 所以我想要的是如果我将一个项目从第一个拖到第二个,并且该项目已经在第二个中,我不希望将项目添加到第二个
  • 我明白,为了让您理解,假设在第一个 QListView 中有 5 个项目,而在第二个项目中它是空的,如果我将一个项目拖到第二个项目,第一个 QListView 将在结束 4 或 5 个项目?
  • @eyllanesc 我希望第一个在拖动后有 5 个项目。虽然看看如何让第一个有 4 会很酷

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


【解决方案1】:

事实证明,如果您想控制拖放行为,您需要设置自己的 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() 中我指定mime 数据将包含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的部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2022-08-13
    • 2022-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多