2016-09-20 3 views
3

Ich versuche, Drag & Drop zu arbeiten zwischen zwei QListViews mit einem benutzerdefinierten QStandardItem. Ich kann nicht die Informationen finden, die ich online außer this document brauche, die ein wenig half, aber jetzt bin ich fest.So löschen Sie ein benutzerdefiniertes QStandardItem in eine QListView

Drag & Drop von einem QListView auf ein anderes funktioniert gut, wenn ich einen QStandardItem verwenden, um meine Daten zu halten, aber wenn ich einen benutzerdefinierten Artikel verwende ich laufen in Schwierigkeiten, weil die Empfangs Model/View eine QStandardItem erzeugt, wenn eine benutzerdefinierte Artikel ist fallen gelassen.

Im Idealfall könnte ich dem empfangenden Modell sagen, dass ich mein benutzerdefiniertes Objekt als Standard-Objekt verwenden soll, und ansonsten tue es einfach, aber ich nehme an, es wird nicht so einfach sein ?! Es scheint, dass alles funktioniert out of the box außer der Schaffung der QStandardItem nach dem Drop, anstatt meine benutzerdefinierte Artikel, so hoffe ich, ich muss nicht neu erfinden (Drag & Drop) Rad, nur um diese zu bekommen Teil rechts ?!

Wenn ich das Rad neu erfinden und die Ansicht dropEvent der Ansicht implementieren muss, um die eingehenden Artikel dann manuell anzufügen, stoße ich auf eine andere Kuriosität. Hier ist mein Test-Code (einschließlich einige Code zum Dekodieren der abgelegten Daten, die ich online gefunden):

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

Die Idee ist, die abgelegten Daten zu dekodieren das ursprüngliche Einzelteil zurück zu erhalten, dann eine Kopie erstellen und diese Kopie anhängen zum empfangenden Modell. Das benutzerdefinierte Objekt wird an das Modell angehängt, wird jedoch nach dem Ereignis drop nicht in der Ansicht angezeigt. Wenn ich ein neues benutzerdefiniertes Element innerhalb des Drop-Even-Objekts erstelle und dieses anhefte, funktioniert alles wie erwartet.

Also habe ich zwei Fragen in Bezug auf die oben:

  1. Ist dieser Ansatz des richtigen den Abwurf von benutzerdefinierten Elementen oder ist es ein einfacher ein aktivieren?
  2. Warum wird die Kopie des benutzerdefinierten Elements im obigen Code nach dem Löschen nicht in der Ansicht angezeigt?

Vielen Dank im Voraus, frank

Antwort

3

es, wie Sie wollen setItemPrototype aussieht. Dadurch wird eine Elementfactory für das Modell bereitgestellt, sodass die benutzerdefinierte Klasse bei Bedarf implizit verwendet wird.

Alles, was Sie tun müssen, ist clone() in Ihrem Artikel Klasse reimplementieren:

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

Eine dann eine Instanz der Klasse, die als Prototyp auf dem Empfängermodell gesetzt:

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

Sie vergessen über den gesamten Datenstrom.

PS:

Ich glaube, ich möchte darauf hinweisen, dass Qt nichts über irgendwelche Python Datenattribute offensichtlich weiß, dass während des Elements Lebensdauer, und so werden diejenigen, die nicht serialisiert erhalten, wenn das Element während übertragen wird eingestellt worden sein eine Drag & Drop-Operation.Wenn Sie möchten, dass die Daten bestehen bleiben möchten, verwenden Sie setData() mit einer benutzerdefinierten Rolle:

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

fragte ich [diese Frage] (http://stackoverflow.com/questions/41991840/pyside-qlistview-creating-new-item -during-Drag-and-Drop-eher-als-Passing-oder) ein wenig früher. Ich habe versucht, Ihrer Lösung zu folgen, aber ich kann immer noch keine benutzerdefinierten Daten über ein Bewegungsereignis verwalten. Ich bin nicht sicher, wie man die 'setData' Methode richtig implementiert. Könntest du ein bisschen darüber hinausgehen, wie man "setData" richtig implementiert? Ich bin mir nicht sicher, was das beste Format für diese Diskussion ist (neue Frage?), Aber hier ist [mein Code mit Änderungen] (https://www.pastiebin.com/5892bb18723f8). – Johndt6

+0

@ Johndt6. Ich fügte ein Beispiel von dem hinzu, was ich zu meiner Antwort meinte. Die Idee ist, die Verwendung dynamischer Python-Attribute vollständig zu vermeiden. Die Verwendung von "@ Eigenschaft" ist nur syntaktischer Zucker. Eine viel einfachere Implementierung wäre es, bei den reinen Qt-APIs zu bleiben: dh die 'QStandardItem'-Komfortmethoden wie 'text()'/'setText()', plus 'data()'/'setData()' für beliebige benutzerdefinierte Werte . Es sollte nicht nötig sein, etwas anderes als "clone()" neu zu implementieren. Die einzigen Dinge, die relevant sind, sind die Artikelflags und Daten. – ekhumoro

Verwandte Themen