2016-09-20 80 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

相關問題