2016-09-20 184 views
3

我试图让拖动&使用自定义的QStandardItem在两个QListView之间工作。 我找不到除this document之外的其他信息,这些信息有一点帮助,但现在我卡住了。如何将自定义的QStandardItem放入QListView中

拖动从一个QListView到另一个工作正常,当我用一个QStandardItem来握住我的数据,但是当我使用一个自定义的项目我碰到麻烦,因为接收模型/视图创建QStandardItem当定制产品&降下降。

理想情况下,我可以告诉接收模型使用我的自定义项目作为默认项目,否则只是做它的事情,但我想它不会那么容易?! 似乎除了创建QStandardItem而不是我的自定义项目之外,所有的东西都可以在盒子外面运行,所以我希望我不必重新发明(拖动&)轮子来获得那个部分权利?!

如果我不得不重新发明轮子,并实现视图的dropEvent然后手动追加传入的项目,我遇到了另一个怪事。这里是我的测试代码(包括一些代码,我在网上找到被丢弃的数据进行解码):

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_()) 

的想法是被丢弃的数据进行解码,以获得原始的项背,然后进行复制和追加该副本到接收模型。 自定义项目被追加到模型中,但它在放置事件后不会显示在视图中。如果我在拖放内创建一个新的自定义项目并追加它,那么一切都按预期工作。

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

  1. 是这种做法是正确的,使的自定义项目的下落或有更简单的吗?
  2. 为什么上面的代码中的自定义项目的副本不会在放置后的视图中显示?

由于提前, 坦率

回答

3

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

所有你需要做的就是在你的物品类别中重新实现clone()

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() 

的然后设置这个类的一个实例为原型在接收模式:

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

你可以忘记关于所有数据流的东西。

PS:

我想我应该指出的是,Qt的明显一无所知,可能在项目的生命周期中已经确定,所以当项目中转移那些不会得到系列化任何Python数据属性拖放操作。如果你想坚持这样的数据,使用setData()与定制角色:

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) 
+0

我问[这个问题](http://stackoverflow.com/questions/41991840/pyside-qlistview-creating-new-item - 时间 - 拖放 - 而不是传递 - 或)稍早一点。我试图按照您的解决方案,但是我仍然无法在移动事件中维护自定义数据。我不知道如何正确实现'setData'方法。你能否扩展一下如何正确实现'setData'?我不确定这次讨论的最佳格式是什么(新问题?),但这里是[我的代码与更改](https://www.pastiebin.com/5892bb18723f8)。 – Johndt6

+0

@ Johndt6。我添加了一个我对我的答案意味着什么的例子。这个想法是完全避免动态python属性的所有用法。 “@ property”的使用只是语法糖。一个更简单的实现是使用纯粹的Qt APIs:即对于任何自定义值,使用'text()'/'setText()'','data()'/'setData()'''QStandardItem' 。应该不需要重新实现除clone()之外的其他任何东西。唯一相关的是项目标志和数据。 – ekhumoro

相关问题