如何将自定义 QStandardItem 放入 QListView [英] How to drop a custom QStandardItem into a QListView

查看:83
本文介绍了如何将自定义 QStandardItem 放入 QListView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用自定义 QStandardItem 在两个 QListView 之间进行拖放操作.除了本文档 这有点帮助,但现在我卡住了.

I am trying to get drag&drop to work between two QListViews using a custom QStandardItem. I can't find the info I need online other than this document which helped a little bit but now I'm stuck.

从一个 QListView 拖放到另一个工作正常当我使用 QStandardItem 保存我的数据时,但是当我使用我遇到麻烦的自定义项目,因为接收模型/视图创建了一个 QStandardItem 删除自定义项时.

Drag&drop from one QListView to another works fine when I use a QStandardItem to hold my data, but when I use a custom item I run into trouble, because the receiving model/view creates a QStandardItem when a custom item is dropped.

理想情况下,我可以告诉接收模型使用我的自定义项目作为默认项目,否则就去做吧,但我想这不会那么容易?!除了创建 QStandardItem 在放下时,而不是我的自定义项目,所以我希望我不必重新发明(拖放)轮子只是为了让那个部分正确?!

Ideally I could tell the receiving model to use my custom item as the default item and otherwise just do it's thing, but I suppose it won't be that easy?! It seems that everything works out of the box except the creation of the QStandardItem upon drop, rather than my custom item, so I am hoping I don't have to re-invent the (drag&drop) wheel just to get that one part right?!

如果我必须重新发明轮子并实现视图的dropEvent 然后手动附加传入的项目,我遇到了另一个奇怪的问题.这是我的测试代码(包括一些用于解码我在网上找到的丢弃数据的代码):

If I do have to re-invent the wheel and implement the view's dropEvent to then manually append the incoming items, I am running into another oddity. Here is my test code (including some code for decoding the dropped data that I found online):

from PySide import QtCore, QtGui

class MyItem(QtGui.QStandardItem):
    '''This is the item I'd like to drop into the view'''

    def __init__(self, parent=None):
        super(MyItem, self).__init__(parent)
        self.testAttr = 'test attribute value'

class ReceivingView(QtGui.QListView):
    '''Custom view to show the problem - i.e. the dropEvent produces a QStandardItem rather than MyItem'''

    def __init__(self, parent=None):
        super(ReceivingView, self).__init__(parent)

    def decode_data(self, bytearray):
        '''Decode byte array to receive item back'''
        data = []
        item = {}

        ds = QtCore.QDataStream(bytearray)
        while not ds.atEnd():

            row = ds.readInt32()
            column = ds.readInt32()

            map_items = ds.readInt32()
            for i in range(map_items):

                key = ds.readInt32()

                value = MyItem()
                ds >> value
                #item[QtCore.Qt.ItemDataRole(key)] = value
                item = value

            data.append(item)

        return data

    def dropEvent(self, event):    
        byteArray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
        for item in self.decode_data(byteArray):
            copiedItem = MyItem(item)
            newItem = MyItem('hello')
            print copiedItem
            print newItem
            self.model().appendRow(copiedItem) # the copied item does not show up, even though it is appended to the model
            #self.model().appendRow(newItem) # this works as expected

        event.accept()

        item = self.model().item(self.model().rowCount() - 1)
        print item

if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)

    mw = QtGui.QMainWindow()
    w = QtGui.QSplitter()
    mw.setCentralWidget(w)

    # models
    model1 = QtGui.QStandardItemModel()
    model2 = QtGui.QStandardItemModel()

    for i in xrange(5):
        #item = QtGui.QStandardItem()
        item = MyItem()
        item.setData(str(i), QtCore.Qt.DisplayRole)
        model1.appendRow(item)

    # views
    view1 = QtGui.QListView()
    view2 = ReceivingView()
    for v in (view1, view2):
        v.setViewMode(QtGui.QListView.IconMode)

    view1.setModel(model1)
    view2.setModel(model2) 

    w.addWidget(view1)
    w.addWidget(view2)

    mw.show()
    mw.raise_()
    sys.exit(app.exec_())

这个想法是解码丢弃的数据以接收原始项目,然后制作副本并将该副本附加到接收模型.自定义项已附加到模型中,但在放置事件后不会显示在视图中.如果我在 drop even 内创建一个新的自定义项目并附加它,一切都会按预期进行.

The idea is to decode the dropped data to receive the original item back, then make a copy and append that copy to the receiving model. The custom item is appended to the model, but it does not show up in the view after the drop event. If I create a new custom item inside the drop even and append that, everything works as expected.

所以我有两个关于上述的问题:

So I got two questions regarding the above:

  1. 这种方法是否适合删除自定义项目,或者是否有更简单的方法?
  2. 为什么上面代码中自定义项的副本在 drop 后没有显示在视图中?

提前致谢,坦率的

推荐答案

看起来你想要 setItemPrototype.这为模型提供了一个项目工厂,以便它在必要时隐式使用您的自定义类.

It looks like you want setItemPrototype. This provides an item factory for the model, so that it will implicitly use your custom class whenever necessary.

您需要做的就是在您的项目类中重新实现 clone():

All you need to do is reimplement clone() in your item class:

class MyItem(QtGui.QStandardItem):
    '''This is the item I'd like to drop into the view'''

    def __init__(self, parent=None):
        super(MyItem, self).__init__(parent)
        self.testAttr = 'test attribute value'

    def clone(self):
        return MyItem()

然后将该类的实例设置为接收模型上的原型:

An then set an instance of that class as the prototype on the receiving model:

    # models
    model1 = QtGui.QStandardItemModel()
    model2 = QtGui.QStandardItemModel()
    model2.setItemPrototype(MyItem())

你可以忘记所有数据流的东西.

You can forget about all the datastream stuff.

附注:

我想我应该指出 Qt 显然对在项目的生命周期中可能已经设置的任何 python 数据属性一无所知,因此当在拖放操作期间传输项目时,这些属性不会被序列化.如果您想保留这样的数据,请使用带有自定义角色的 setData():

I suppose I should point out that Qt obviously knows nothing about any python data attributes that may have been set during the item's lifetime, and so those won't get serialized when the item is transferred during a drag and drop operation. If you want to persist data like that, use setData() with a custom role:

class MyItem(QtGui.QStandardItem):
    _TestAttrRole = QtCore.Qt.UserRole + 2

    def clone(self):
        item = MyItem()
        item.testArr = 'test attribute value'
        return item

    @property
    def testAttr(self):
        return self.data(self._TestAttrRole)

    @testAttr.setter
    def testAttr(self, value):
        self.setData(value, self._TestAttrRole)

这篇关于如何将自定义 QStandardItem 放入 QListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆