python - PyQt5 拖放到系统文件资源管理器中(带有延迟编码)?

标签 python pyqt pyqt5

我想让用户通过将项目从 PyQt 拖到系统文件资源管理器来创建文件。由于某些文件非常大,我还需要延迟将数据设置为用户完成放置时,而不是立即开始拖动。

这个例子似乎就是我所需要的:https://doc.qt.io/archives/4.6/draganddrop-delayedencoding.html

我尝试将其转换为简单的 PyQt5 版本,其中将 QPushButton 拖到文件夹中将创建一个纯文本文件,但它对我不起作用...当我运行它时,删除不会执行任何操作,我的光标如下所示:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import typing
import time


class MimeData(QtCore.QMimeData):
    dataRequested = QtCore.pyqtSignal(str)

    def formats(self) -> typing.List[str]:
        return QtCore.QMimeData.formats(self) + ["text/plain"]

    def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
        self.dataRequested.emit(mime_type)
        return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)


class SourceWidget(QtWidgets.QWidget):
    mimeData: MimeData = None

    def __init__(self, parent=None):
        super().__init__(parent)

        layout = QtWidgets.QVBoxLayout()
        button = QtWidgets.QPushButton("Drag Me")
        button.pressed.connect(self.start_drag)

        layout.addWidget(button)
        self.setLayout(layout)

    @QtCore.pyqtSlot()
    def create_data(self, mime_type):
        if mime_type == "text/plain":
            time.sleep(0.25)  # Simulate large file
            self.mimeData.setData("text/plain", b"my text file contents")

    @QtCore.pyqtSlot()
    def start_drag(self):
        self.mimeData = MimeData()
        self.mimeData.dataRequested.connect(self.create_data)

        drag = QtGui.QDrag(self)
        drag.setMimeData(self.mimeData)
        drag.exec(QtCore.Qt.CopyAction)


if __name__ == "__main__":
    app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)

    w = SourceWidget()
    w.show()

    app.exec_()

最佳答案

这就是我将文件从 PyQt5 拖放到文件资源管理器中的结果,并且只有在释放鼠标以完成放置时才写入文件。


import time

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt

import tempfile
import os

# Use win32api on Windows because the pynput and mouse packages cause lag
# https://github.com/moses-palmer/pynput/issues/390
if os.name == 'nt':
    import win32api


    def mouse_pressed():
        return win32api.GetKeyState(0x01) not in [0, 1]
else:
    import mouse


    def mouse_pressed():
        return mouse.is_pressed()


class DelayedMimeData(QtCore.QMimeData):
    def __init__(self):
        super().__init__()
        self.callbacks = []

    def add_callback(self, callback):
        self.callbacks.append(callback)

    def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
        mp = mouse_pressed()
        if not mp:
            for callback in self.callbacks.copy():
                self.callbacks.remove(callback)
                callback()

        return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)


class Navigator(QtWidgets.QTreeWidget):
    def __init__(self):
        super().__init__()

        self.setHeaderLabels(["Name"])
        QtWidgets.QTreeWidgetItem(self, ['Test1'])
        QtWidgets.QTreeWidgetItem(self, ['Test2'])
        QtWidgets.QTreeWidgetItem(self, ['Test3'])

        self.setAcceptDrops(True)
        self.setDragEnabled(True)
        self.setDragDropMode(self.DragDrop)
        self.setDefaultDropAction(Qt.MoveAction)
        self.setSelectionMode(self.ExtendedSelection)
        self.setSelectionBehavior(self.SelectRows)

        self.setContextMenuPolicy(Qt.CustomContextMenu)

    def startDrag(self, actions):
        drag = QtGui.QDrag(self)
        names = [item.text(0) for item in self.selectedItems()]
        mime = DelayedMimeData()
        path_list = []
        for name in names:
            path = os.path.join(tempfile.gettempdir(), 'DragTest', name + '.txt')
            os.makedirs(os.path.dirname(path), exist_ok=True)
            print(path)

            def write_to_file(path=path, name=name, widget=self):
                with open(path, 'w+') as f:
                    print("Writing large file(s)...")
                    time.sleep(2)  # Sleep to simulate long file write
                    f.write(f"Contents of {name}")

            mime.add_callback(write_to_file)
            path_list.append(QtCore.QUrl.fromLocalFile(path))

        mime.setUrls(path_list)
        mime.setData('application/x-qabstractitemmodeldatalist',
                     self.mimeData(self.selectedItems()).data('application/x-qabstractitemmodeldatalist'))
        drag.setMimeData(mime)
        drag.exec_(Qt.MoveAction)
        super().startDrag(actions)


app = QtWidgets.QApplication([])

nav = Navigator()
nav.show()
app.exec_()

关于python - PyQt5 拖放到系统文件资源管理器中(带有延迟编码)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64252654/

相关文章:

python - 在带有日期的多列上具有多个条件的子集 pandas 数据框

python - 如何捕获 PyQt5 QMainWindow 失去焦点

python-2.7 - 在 Windows 上安装 NodeboxOpenGL

python - 在 PyQt5 和 PySide2 中重写 PaintEvent

python - 绘制实时传感器数据时,PyQtGraph 停止更新并卡住

python - 如何知道用户何时完成调整窗口大小?

python - 使用 Selenium/PhantomJS 进行网络捕获

python - 导入 GoogleNews-vectors-negative300.bin

Python 多处理不使用 RHEL6 上的所有内核

python - PyQt QTableView - 捕获 KeyDown/KeyPress 事件