拖放(20):【例】拖放入门

Qt 拖放入门

基本概念

拖-放技术是基本的传输协议,它把一个数据对象拖动到目标处,其过程如下:终端用户在源应用程序的窗口中选择一个数据对象,用鼠标点中此对象,然后按住鼠标把对象拖动到目标应用程序的窗口中,再松开鼠标按钮。

所以拖-放,实质是指用鼠标拖动的方法,在不同程序的窗口之间、同一个程序的不同窗口之间或不同控件之间,进行移动、复制和粘贴等操作的技术。

被拖动的数据对象按指定的数据格式提供数据,拖放操作结束时,接收拖放的窗口按指定的数据格式提取有关数据,并根据提取的数据生成相应的对象。

Windows系统拖放到Qt程序

Windows的一个显著特色就在于支持鼠标拖放,使用拖放可以简化许多烦琐的操作。Qt也支持拖放操作,从windows系统拖动数据对象到Qt的应用程序,是很方便的。

QTextEdit 类已经实现了关于拖放操作数据对象的函数,而且默认支持拖放操作,方便用来直接演示:

  • virtual bool canInsertFromMimeData(const QMimeData *source) const

  • virtual QMimeData * createMimeDataFromSelection() const

  • virtual void insertFromMimeData(const QMimeData *source)

  • virtual void dragEnterEvent(QDragEnterEvent *e) override

  • virtual void dragLeaveEvent(QDragLeaveEvent *e) override

  • virtual void dragMoveEvent(QDragMoveEvent *e) override

  • virtual void dropEvent(QDropEvent *e) override

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextEdit t;            // QTextEdit默认支持拖放功能,用来演示
    t.resize(300,200);
    t.setWindowFlags(Qt::WindowStaysOnTopHint);  // 为方便操作,窗口前置
    t.show();
    return a.exec();
}

从上面的示例可以看出 Qt 和 Windows 操作系统同时对拖放技术的支持,如果拖放的数据对象格式是文本类型的,QTextEdit会直接复制其文本,如果是其他类型的,QTextEdit会自动将其URL添加到文本框中。

拖放的对象:MIME

Qt 和 windows 操作系统之所以可以使用拖放传输数据,是因为拖放的数据对象都是基于MIME的标准。

MIME (Multipurpose Internet Mail Extensions) 用来表示文档、文件或字节流的性质和格式,现已成为互联网通讯的标准。

互联网号码分配机构(IANA)是负责跟踪所有官方MIME类型的官方机构,您可以在媒体类型页面中找到最新的完整类型列表。

语法

type/subtype

MIME的语法组成结构非常简单;由类型与子类型两个字符串中间用'/'分隔而组成。不允许空格存在。

常用的数据类型:

类型描述典型示例
text表明文件是普通文本,理论上是人类可读text/plain, text/html, text/css, text/javascript
image表明是某种图像。不包括视频,但是动态图(比如动态gif)也使用image类型image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon, image/vnd.microsoft.icon
audio表明是某种音频文件audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
video表明是某种视频文件video/webm, video/ogg
application表明是某种二进制数据application/octet-stream, application/pkcs12, application/vnd.mspowerpoint, application/xhtml+xml, application/xml, application/pdf

对于text文件类型若没有特定的subtype,就使用 text/plain

类似的,二进制文件没有特定或已知的 subtype,即使用 application/octet-stream

获取MIME的数据类型

Qt中表示MIME数据的类是QMimeData类,在拖放的过程中,在QDropEvent、QDragMoveEvent 以及QDragEnterEvent中作为参数传输。三者继承关系如下:

image-20201209102637606

TextEdit

TextEdit 子类化 QTextEdit,重写dropEvent事件函数,从而获得QMimeData 类。

定义

class TextEdit : public QTextEdit
{
    Q_OBJECT
public:
    explicit TextEdit(QWidget *parent = nullptr);
    void dropEvent(QDropEvent *e) override;
};

基础实现

#include "TextEdit.h"

TextEdit::TextEdit(QWidget *parent)
    :QTextEdit(parent)
{
}

void TextEdit::dropEvent(QDropEvent *e)
{
    QTextEdit::dropEvent(e);
    const QMimeData *mime = e->mimeData();
    foreach(const QString str,mime->formats())
        append(str);
}
image-20201209121314937

但是在Windows系统上,QMimeData::formats() 将使用x-qt-windows-mime子类型返回MIME数据中可用的自定义格式,以指示它们表示非标准格式的数据。 格式将采用以下形式:

application/x-qt-windows-mime;value="<custom type>"

这种格式不是标准格式,万幸Qt还有QMimeDatabase 和 QMimeType类,这两个类中的函数就可以分辨出对象数据的MIME类型的标准格式:

  • QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device) const
  • QMimeType QMimeDatabase::mimeTypeForFile(const QString &fileName, QMimeDatabase::MatchMode mode = MatchDefault)
  • QString QMimeType::name() const

改进实现

image-20201209123401953

void TextEdit::dropEvent(QDropEvent *e)
{
    QTextEdit::dropEvent(e);
    const QMimeData *mime = e->mimeData();
    QString filePath = mime->urls().at(0).toLocalFile();
    QFile file(filePath);
    QMimeDatabase mdd;
    QMimeType mType;
    if(file.size()==0)  // 大小为0的文件,是无法使用数据内容分辨MIME格式的
        mType = mdd.mimeTypeForFile(file,QMimeDatabase::MatchExtension);  // 使用文件的名称分辨MIME格式
    else{
        mType = mdd.mimeTypeForFile(file,QMimeDatabase::MatchContent); ; // 使用数据内容来分辨MIME格式
    }
    append(mType.name() + "\n\n");
}

这种读取数据内容的方式,可以获取正确的文件类型,而不用管文件后缀名是否存在,或者后缀名是否正确。

总结

拖放技术是基于MIME标准的数据传输协议,理解了MIME数据对象的内容和格式,将有助于对拖放操作的理解。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值