在PyQt5 TreeView中拖放?

时间:2018-01-05 21:44:40

标签: python drag-and-drop pyqt pyqt5 qtreeview

我正在尝试使用PyQt5实现文件目录。我想在此树中加入拖放功能以支持内部和外部文件(即如果我的桌面上有一些文件,我希望能够将它们放入文件夹中在我的PyQt视图中)。这就是我目前所拥有的:

from PyQt5.QtWidgets import QTreeView,QFileSystemModel,QApplication, 
QMenu, QAbstractItemView
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from src import config

class Tree(QTreeView):
    def __init__(self):
        QTreeView.__init__(self)
        cfg = config.get()

        model = QFileSystemModel()
        model.setRootPath("/Users/")

        self.setModel(model)
        self.setRootIndex(model.index("/Users/"))
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.open_menu)

        self.setSelectionMode(self.SingleSelection)
        self.setDragDropMode(QAbstractItemView.InternalMove)
        self.setDragEnabled(True)
        self.setAcceptDrops(True)
        self.setDropIndicatorShown(True)


    def open_menu(self):
        menu = QMenu()
        menu.addAction("Create new folder")
        menu.exec_(QCursor.pos())
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Main()
    w.show()
    sys.exit(app.exec_())

使用上面的代码,我可以显示目录及其内容。我可以拖动一个项目,但丢弃它什么都不做,没有看到掉落指示。目前还不清楚如何

一个。在视图中拖放工作和

湾让它使用该上下文之外的项目(例如从桌面开始)。

2 个答案:

答案 0 :(得分:1)

根据docs

  

readOnly:bool

     

此属性保存目录模型是否允许写入文件系统

     

如果此属性设置为false,则目录模型将允许   重命名,复制和删除文件和目录。

     

默认情况下,此属性为true

因此,如果您希望能够移动文件,则必须将其设置为False:

model.setReadOnly(False)

您必须覆盖dragEnterEvent方法,如果相对于本地资源有QUrl,您必须接受它。

然后你必须覆盖dropEvent方法,如果事件没有源,那么它暗示它来自外部源作为本地文件,然后实现逻辑以移动文件或目录检查是否文件或目录是否存在或不创建新的路径。

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

答案 1 :(得分:0)

在树状视图子类中,您必须实现dragEnterEvent dragMoveEventdropEvent

class Tree(QTreeView):
    def __init__(self):
        QTreeView.__init__(self)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            # to get a list of files:
            drop_list = []
            for url in event.mimeData().urls():
                drop_list.append(str(url.toLocalFile()))
            # handle the list here
        else:
            event.ignore()