使用Qt实现从资源管理器中拖动文件到应用程序的功能


类型:Python,C++ & Qt4,创建时间:Jan. 1, 2012, 8:52 p.m.

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/54/。

我是EditPlus和FileZilla的用户。这两个软件都支持文件拖拽。我们可以从资源管理器中拖动一个文件到EditPlus的窗口,EditPlus就会自动打开这个文件。或者拖到FileZilla的远程窗口内,FileZilla就会自动将文件上传到服务器。我经常希望自己的软件也支持拖动的操作。

作为基本功能,大多数操作系统都各自定义了拖放所需的通信协议。Qt对此做了一个很好的封装。基本的流程是:当用户从其它应用程序拖动文件、文本、图像等到Qt程序时,Qt会自动产生一个DrapEnterEvent,应用程序可以判断数据是不是可以处理的。如果能处理,就反馈给Qt,这样的话,用户就会看到一个接受拖放的标识。待用户放开鼠标时,Qt再产生一个DropEvent。最后应用程序从事件中取出数据进行处理。

那么应用程序如何判断程序是否可以处理拖放的数据呢?很简单,数据中包含了MIME类型。MIME类型是一个用于标识二进制数据类型的Internet标准。很多朋友可能习惯通过文件的扩展名来判断数据类型,但是扩展名只有短短的几个字符,常常有歧义。通常,如果应用程序要处理文本,就判断MIME类型是不是"text/palin",如果要处理JPEG图像,就判断MIME类型是不是"image/jpeg",等等。同一段数据通常包含多种MIME类型,比如拖动富文本时,数据中可能包含纯文本、HTML文本、图像。应用程序可以选择处理所支持的数据格式。

在Windows平台下,拖放首先的数据多种多样,有很多没有标准的MIME类型。这时Qt自动转换成形如application/x-qt-windows-mime;value="FileNameW"这样的MIME类型。实际上,这就是拖放文件时文件名的MIME类型。为了更跨平台一点,文件名也可以表示为"text/uri-list"类型。

为了让一个控件能够接受被拖动的文件,我们需要重新实现QWidget的几个方法。这是简单的PyQt代码,只适用于windows平台,稍微修改为"text/uri-list"就可以跨平台:

specialMimeType="application/x-qt-windows-mime;value=\"FileNameW\""

class WrtierWindow(QMainWindows):
    def __init__(self):
        QMainWindow.__init__(self, parent, flags)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat(specialMimeType):
            event.acceptProposedAction()

    def dropEvent(self, event):
        if not event.mimeData().hasFormat(specialMimeType):
            return
        filenameBytes=event.mimeData().data(specialMimeType)
        filename=QTextCodec.codecForName("utf-16").toUnicode(filenameBytes)
        print unicode(filename).encode("gbk")

可惜的是,目前我还不知道要怎么拖拉一个文件到文件管理器里面。

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/54/。


老鱼(July 19, 2014, 9:12 p.m.)

直接用text/uri-list会更好一些。


何不来发表一下您对本文的看法(使用Markdown语法,分段空两行):