【发布时间】:2020-10-07 21:36:17
【问题描述】:
我想让用户通过将项目从 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_()
【问题讨论】:
-
不幸的是,我不认为你可以有一个简单的答案(至于你的original question。在 Qt 之外拖放并不容易实现,因为它完全取决于拖放的平台管理。长话短说:你不能用 PyQt 做到这一点;至少,不容易。尽管如此,你的代码中仍然存在一些问题,最重要的是你使用了没有参数的
pyqtSlot()装饰器,但create_data需要一个字符串。 -
您可以尝试做的是创建一个临时文件(如果源还不存在),并将该临时文件的 url 添加到 mimeData url列表。同时,就在开始拖动操作之前,您可以创建一个单独创建文件的线程,并使用一个简单的while循环等待直到线程被(成功完成。 PS:关于
pyqtSlot()问题,请记住这些装饰器很少需要,所以如果你真的不需要它们(如本例所示),请避免使用它们。 -
嗯,该链接显示了如何设置包含图像的 mimeData;平台对此做什么完全取决于平台如何根据拖动数据管理拖放操作。我不知道您使用的是什么平台,我猜您在 Windows 下(您从未指定过,这在某种程度上很重要),我只能假设该平台会自动建议 根据拖拽的内容用图像数据创建一个新文件。事实上,如果仔细观察,
createData函数只是更新 mime 内容,并没有实际创建文件。 -
我不知道你要创建什么样的数据,但如果是自定义的,我相信唯一的解决方案是用你要创建的数据创建一个临时文件使用,为该文件提供适当的
QUrl,并以在删除完成后立即删除源文件的方式连接放置操作。 -
好吧,看起来你不需要太多的工作:只需使用 python 自己的
with open(path, 'w') as f: f.write(data)并在之后返回路径,然后使用fromLocalFile(path)构造 QUrl并将 URL 的路径添加为列表。我不知道 Qt 在 Windows 下的行为如何;如果 dropEvent 在将数据传递给系统后立即返回(就像我认为的那样),您需要找到一种方法来确保在删除临时文件之前已完成复制,但请注意您必须考虑->