2017-11-28 6 views
0

In meinem QtreeView verwende ich ein "QStandardItemModel" zum Anzeigen mehrerer Elemente mit einzelnen Eigenschaften. Ich möchte vermeiden, dass der Artikel nicht gemischt wird. z.B. Bananen sollten unter den Ländern Asien (höheres Niveau) auf Gemüse (gleiches Kind Niveau), aber nicht beweglich sein, nach Asien zu bewegen - Obst ist ok (gleiche Kind-Ebene)Wie zu vermeiden Drop auf Knoten

Probe

ich gearbeitet habe mit .itemChanged aber es scheint zu spät. Ich brauche ein Signal vor wird es fallengelassen und das Element wo wird es fallen gelassen werden. Ich habe versucht, eventFilter und

event.type() == QtCore.QEvent.DragMove: 

erhalten, aber wie bekomme ich den Index des Elements, in dem der Punkt fallen gelassen werden wird, zu entscheiden, seine im selben Kind Ebene?

Antwort

0

Um dieses Problem zu lösen, habe ich einen benutzerdefinierten Mimetyp erstellt, der die Informationen des Index und die Tiefe der Tiefe sendet, und es werden nur die Indizes verschoben, die die gleiche Ebene wie die Kinder des Ziels haben.

class TreeView(QTreeView): 
    customMimeType = "application/x-customqstandarditemmodeldatalist" 

    def __init__(self, *args, **kwargs): 
     QTreeView.__init__(self, *args, **kwargs) 
     self.setSelectionMode(QAbstractItemView.SingleSelection) 
     self.setDragEnabled(True) 
     self.viewport().setAcceptDrops(True) 
     self.setDropIndicatorShown(True) 
     self.setDragDropMode(QTreeView.InternalMove) 

    def itemsToPixmap(self, indexes): 
     rect = self.viewport().visibleRegion().boundingRect() 
     pixmap = QPixmap(rect.size()) 
     pixmap.fill(Qt.transparent) 
     painter = QPainter(pixmap) 
     for index in indexes: 
      painter.drawPixmap(self.visualRect(index), self.viewport().grab(self.visualRect(index))) 
     return pixmap 

    def mimeTypes(self): 
     mimetypes = QTreeView.mimeTypes(self) 
     mimetypes.append(TreeView.customMimeType) 
     return mimetypes 

    def startDrag(self, supportedActions): 
     drag = QDrag(self) 
     mimedata = self.model().mimeData(self.selectedIndexes()) 

     encoded = QByteArray() 
     stream = QDataStream(encoded, QIODevice.WriteOnly) 
     self.encodeData(self.selectedIndexes(), stream) 
     mimedata.setData(TreeView.customMimeType, encoded) 

     drag.setMimeData(mimedata) 
     px = self.itemsToPixmap(self.selectedIndexes()) 
     drag.setPixmap(px) 
     drag.setHotSpot(self.viewport().mapFromGlobal(QCursor.pos()) - QPoint(self.horizontalOffset(), 
                       self.verticalOffset())) 
     drag.exec_(supportedActions) 

    def encodeData(self, items, stream): 
     stream.writeInt32(len(items)) 
     for item in items: 
      p = item 
      rows = [] 
      while p.isValid(): 
       rows.append(p.row()) 
       p = p.parent() 
      stream.writeInt32(len(rows)) 
      for row in reversed(rows): 
       stream.writeInt32(row) 

    def dropEvent(self, event): 
     if event.source() == self: 
      if event.mimeData().hasFormat(TreeView.customMimeType): 
       encoded = event.mimeData().data(TreeView.customMimeType) 
       items = self.decodeData(encoded, event.source()) 
       ix = self.indexAt(event.pos()) 
       current = self.model().itemFromIndex(ix) 
       p = current 
       level = 1 
       while p: 
        p = p.parent() 
        level += 1 
       for item, ilevel in items: 
        if level == ilevel: 
         item.parent().takeRow(item.row()) 
         current.appendRow(item) 
       self.clearSelection() 
       event.acceptProposedAction() 
     else: 
      event.ignore() 

    def decodeData(self, encoded, tree): 
     items = [] 
     rows = [] 
     stream = QDataStream(encoded, QIODevice.ReadOnly) 
     while not stream.atEnd(): 
      nItems = stream.readInt32() 
      for i in range(nItems): 
       path = stream.readInt32() 
       row = [] 
       for j in range(path): 
        row.append(stream.readInt32()) 
       rows.append(row) 

     for row in rows: 
      it = self.model().item(row[0]) 
      for r in row[1:]: 
       it = it.child(r) 
      items.append((it, len(row))) 
     return items 

Ein vollständigeres Beispiel kann in der folgenden link

+0

Ich habe Probleme mit Unterklassen, weil ich 'loadUIC' verwende, gelöst durch Kopieren der Einstellungen (Höhe, Breite). Aber das große ist, dass ich keine Lösung dafür gefunden habe, dass es nicht mehr möglich ist, die Einträge zu sortieren. Ich habe 'current.insertRow (current.row(), item)' ausprobiert, aber es fügt es als erstes Kind ein. "level" und "level" sind unterschiedlich, also muss es etwas anderes geben ... – Hans

+0

Wenn Sie ein QTreeView über Qt Designer erstellen, dann bewerben Sie es einfach, um meine Klasse zu verwenden. – eyllanesc

+0

Ich habe es mit 'self.structureTreeModel = TreeModel()' zugewiesen, aber es erscheint als zusätzliches Widget in meinem Fenster. – Hans

0

Folgende Änderungen erlauben sich zu bewegen ein Element innerhalb einer Reihe von Childs, aber nicht nach außen entnommen werden. Funktioniert immer noch, um den Cursor zu ändern, wenn das Ziel nicht auf derselben Ebene ist.

def dropEvent(self, event): 
    if event.source() == self: 
     if event.mimeData().hasFormat(TreeView.customMimeType): 
      encoded = event.mimeData().data(TreeView.customMimeType) 
      items = self.decodeData(encoded, event.source()) 
      ix = self.indexAt(event.pos()) 
      current = self.model().itemFromIndex(ix) 
      p = current 
      level = 0 
      while p: 
       p = p.parent() 
       level += 1 
      for item, ilevel in items: 
       if level == ilevel: 
        item.parent().takeRow(item.row()) 
        current.parent().insertRow(current.row(),item) 
      self.clearSelection() 
      event.acceptProposedAction() 
    else: 
     event.ignore()