将Qlabel图像拖到桌面的最小示例

发布于 2025-02-04 08:21:29 字数 1194 浏览 2 评论 0原文

我正在尝试制作一个Qlabel,该QLABEL在主窗口外面的外部可拖动,但是我所有的尝试都无法将其拖动到文件Explorer路径并将其保存为图像。是否有允许该功能的第三方文档?

我的最后一次尝试如下:

class DraggableLabel(QtWidgets.QLabel):
    def __init__(self,image):
        QtWidgets.QLabel.__init__(self)
        self.setPixmap(image)    
        self.setAcceptDrops(True)
        self.show()

    def mousePressEvent(self, event):
        if event.button() == QtGui.Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not (event.buttons() & QtGui.Qt.LeftButton):
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QtWidgets.QApplication.startDragDistance():
            return
        drag = QtGui.QDrag(self)
        mimedata = QtCore.QMimeData()
        mimedata.setImageData(self.pixmap().toImage())

        drag.setMimeData(mimedata)
        drag.setHotSpot(event.pos())
        drag.exec_(QtGui.Qt.CopyAction | QtGui.Qt.MoveAction)
        
        source = drag.source()
        print("source = %s" % source)
        target = drag.target()   # how to return this target as file explorer path ?
        print("target = %s" % target)

I'm trying to make a Qlabel that is draggable outside of the main widget but all my attempts fail to drag it to the file explorer path and save it as image. Is there any third party documentation that allow that functionality?

My last attempt is as follows:

class DraggableLabel(QtWidgets.QLabel):
    def __init__(self,image):
        QtWidgets.QLabel.__init__(self)
        self.setPixmap(image)    
        self.setAcceptDrops(True)
        self.show()

    def mousePressEvent(self, event):
        if event.button() == QtGui.Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not (event.buttons() & QtGui.Qt.LeftButton):
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QtWidgets.QApplication.startDragDistance():
            return
        drag = QtGui.QDrag(self)
        mimedata = QtCore.QMimeData()
        mimedata.setImageData(self.pixmap().toImage())

        drag.setMimeData(mimedata)
        drag.setHotSpot(event.pos())
        drag.exec_(QtGui.Qt.CopyAction | QtGui.Qt.MoveAction)
        
        source = drag.source()
        print("source = %s" % source)
        target = drag.target()   # how to return this target as file explorer path ?
        print("target = %s" % target)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一腔孤↑勇 2025-02-11 08:21:29

target() 适用于作为应用程序一部分的对象(实际上,它返回QObject类型,这意味着只能检索 nestral qt类型)。这意味着您对外部目标的下降一无所知。

唯一的QT(和跨平台符合)可能的解决方案是创建一个保存图像的临时文件,并使用 setUrls() 带有包含临时文件路径的单个项目列表。

这种方法的唯一(不可避免的)警告是您无法设置目标文件名:文件名是由QT内部决定的,唯一可能的自定义基于一个模板文件名,该模板名称将导致一些“随机”字母。和使用的数字代替xxxxxx占位符。

class DraggableLabel(QtWidgets.QLabel):
    def __init__(self, image):
        super().__init__(pixmap=image)
        self.tempFiles = []
        self.setAcceptDrops(True)
        QtWidgets.QApplication.instance().aboutToQuit.connect(
            self.deleteTemporaryFiles)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not event.buttons() & QtCore.Qt.LeftButton:
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QtWidgets.QApplication.startDragDistance():
            return

        drag = QtGui.QDrag(self)
        mimedata = QtCore.QMimeData()
        mimedata.setImageData(self.pixmap().toImage())

        tempFile = QtCore.QTemporaryFile(
            QtCore.QDir.tempPath()
            + QtCore.QDir.separator()
            + 'exportXXXXXX.png')
        # temporary files are removed upon their destruction, since the copy
        # or move operations can take an undefined amount of time, we need to
        # keep a reference and eventually destroy them after a reasonable
        # amount of time
        self.tempFiles.append(tempFile)

        self.pixmap().save(tempFile)
        mimedata.setUrls([QtCore.QUrl.fromLocalFile(tempFile.fileName())])

        drag.setPixmap(self.pixmap().scaled(64, 64, 
            QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
        drag.setMimeData(mimedata)
        drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction)

        # an arbitrary amount of time for the removal of the temporary file
        QtCore.QTimer.singleShot(30000, self.deleteTemporaryFiles)

    def deleteTemporaryFiles(self):
        while self.tempFiles:
            self.tempFiles.pop().deleteLater()

最后,极其重要说明:考虑到拖放操作完全基于临时文件,每当文件删除在支持直接的程序上时,这可以代表A 认真问题文件从文件管理器拖动,并且无法正确管理该文件的访问:由于上面的代码出于性能/安全/安全原因删除了临时文件,因此该源文件可能无效。如果目标程序接受您的应用程序中的滴滴,则可能只要调用deleteTemporaryFiles,该程序就无法访问它,并且结果是完全出乎意料的。该程序可能会崩溃,您的程序可能会崩溃,或者您甚至可能会得到 total 系统崩溃。
虽然提供的代码确实有效,但您必须注意这一方面,并​​最终警告用户其使用情况。

The target() of QDrag only works for objects that are part of the application (in fact, it returns a QObject type, meaning that only internal Qt types can be retrieved). This means that you cannot know anything about drops on external targets.

The only Qt (and cross-platform compliant) possible solution is to create a temporary file on which the image is saved, and use setUrls() with a single-item list that contains the temporary file path.

The only (and unavoidable) caveat of this approach is that you cannot set the target file name: the file name is internally decided by Qt, and the only possible customization is based on a template file name that will result in some "random" letters and numbers used instead of the XXXXXX placeholder.

class DraggableLabel(QtWidgets.QLabel):
    def __init__(self, image):
        super().__init__(pixmap=image)
        self.tempFiles = []
        self.setAcceptDrops(True)
        QtWidgets.QApplication.instance().aboutToQuit.connect(
            self.deleteTemporaryFiles)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not event.buttons() & QtCore.Qt.LeftButton:
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QtWidgets.QApplication.startDragDistance():
            return

        drag = QtGui.QDrag(self)
        mimedata = QtCore.QMimeData()
        mimedata.setImageData(self.pixmap().toImage())

        tempFile = QtCore.QTemporaryFile(
            QtCore.QDir.tempPath()
            + QtCore.QDir.separator()
            + 'exportXXXXXX.png')
        # temporary files are removed upon their destruction, since the copy
        # or move operations can take an undefined amount of time, we need to
        # keep a reference and eventually destroy them after a reasonable
        # amount of time
        self.tempFiles.append(tempFile)

        self.pixmap().save(tempFile)
        mimedata.setUrls([QtCore.QUrl.fromLocalFile(tempFile.fileName())])

        drag.setPixmap(self.pixmap().scaled(64, 64, 
            QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
        drag.setMimeData(mimedata)
        drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction)

        # an arbitrary amount of time for the removal of the temporary file
        QtCore.QTimer.singleShot(30000, self.deleteTemporaryFiles)

    def deleteTemporaryFiles(self):
        while self.tempFiles:
            self.tempFiles.pop().deleteLater()

Finally, an extremely important note: considering that the drag operation is completely based on temporary files, this can represent a serious issue whenever the file is dropped on a program that supports direct file dragging from the file manager and doesn't properly manage the access to that file: since the code above deletes the temporary file(s) for performance/safety/security reasons, that source file can become invalid. If the target program accepts a drop from your application, it is possible that the program won't be able to access it whenever the deleteTemporaryFiles gets called and the result is completely unexpected. That program could crash, your program could crash, or you might even get a total system crash.
While the provided code does work, you must be aware of this aspect, and eventually warn the user about its usage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文