Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTreeWidget Drag and Drop



  • Hi,
    I don't have that much experience with pyQt5 so bear with me. ;-)
    I'm trying to have drag and drop working on my application. I have an example from the web (can't remember where) with QTreeView. I adapted it for QTreeWidget, but it doesn't work.
    My understanding is that drag and drop is not limitted to mime data. Correct?

    QTreeWidget Drag and Drop example (not working)

    from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QApplication, QAbstractItemView
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    
    class myTreeWidget(QTreeWidget):
        def __init__(self):
            QTreeWidget.__init__(self)
            self.setSelectionMode(self.SingleSelection)
            self.setDragDropMode(QAbstractItemView.InternalMove)
            self.setDragEnabled(True)
            self.setAcceptDrops(True)
            self.setDropIndicatorShown(True)
    
            self.setModel(self.model)
            self.setRootIndex(self.model.index(QDir.currentPath()))
            self.model.setReadOnly(False)
            parent = self.invisibleRootItem()
            child = QTreeWidgetItem(parent)
            child.setData()
            data = [
               ['a','b','c','d'],
               ['e','f','g','h'],
               ['i','j','k','l'],
            ]
            self.setColumnCount(len(data[0]))
    
            parent = self.invisibleRootItem()
            for d in data:
                child = QTreeWidgetItem(parent)
                child.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                for col, v in enumerate(d):
                    child.setText(col, v)
                parent.addChild(child)
    
        def dragEnterEvent(self, event):
            print('dragEnterEvent happened')
            event.acceptProposedAction()
    
        def dragMoveEvent(self, event):
            print('dragMoveEvent happened')
            event.acceptProposedAction()
    
        def dropEvent(self, event):
            print('dropEvent happened')
            widgetItemThatMoved=event.source().currentItem()
            parentThatReceivedIt=self.itemAt(event.pos())
            self.theFunc(parentThatReceivedIt,widgetItemThatMoved )
            event.acceptProposedAction()
    
        def functionToCallWhenDropped(self,theFunc):
            #this method allows you to pass a reference to this class so you assign it to a local variable for easy calling.
            self.theFunc=theFunc
    
    app = QApplication(sys.argv)
    demo = myTreeWidget()
    demo.show()
    app.exec_()
    

    QTreeView Drag and Drop example (working)

    from PyQt5.QtWidgets import QTreeView, QFileSystemModel, QApplication, QMenu, QAbstractItemView
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    # from src import config
    
    class Tree(QTreeView):
        def __init__(self):
            QTreeView.__init__(self)
            model = QFileSystemModel()
            model.setRootPath(QDir.currentPath())
    
            self.setModel(model)
            self.setRootIndex(model.index(QDir.currentPath()))
            model.setReadOnly(False)
    
            self.setSelectionMode(self.SingleSelection)
            self.setDragDropMode(QAbstractItemView.InternalMove)
            self.setDragEnabled(True)
            self.setAcceptDrops(True)
            self.setDropIndicatorShown(True)
    
        def dragEnterEvent(self, event):
            m = event.mimeData()
            if m.hasUrls():
                for url in m.urls():
                    if url.isLocalFile():
                        event.accept()
                        return
            event.ignore()
    
        def dropEvent(self, event):
            if event.source():
                QTreeView.dropEvent(self, event)
            else:
                ix = self.indexAt(event.pos())
                if not self.model().isDir(ix):
                    ix = ix.parent()
                pathDir = self.model().filePath(ix)
                m = event.mimeData()
                if m.hasUrls():
                    urlLocals = [url for url in m.urls() if url.isLocalFile()]
                    accepted = False
                    for urlLocal in urlLocals:
                        path = urlLocal.toLocalFile()
                        info = QFileInfo(path)
                        n_path = QDir(pathDir).filePath(info.fileName())
                        o_path = info.absoluteFilePath()
                        if n_path == o_path:
                            continue
                        if info.isDir():
                            QDir().rename(o_path, n_path)
                        else:
                            qfile = QFile(o_path)
                            if QFile(n_path).exists():
                                n_path += "(copy)" 
                            qfile.rename(n_path)
                        accepted = True
                    if accepted:
                        event.acceptProposedAction()
    
    app = QApplication(sys.argv)
    demo = Tree()
    demo.show()
    app.exec_()
    

    Thanks in advance!
    Denis


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Did you already saw the Qt documentation about Drag'N'Drop with convenience view ?


Log in to reply