Qt 4.x:如何实现拖放到桌面或文件夹中?

时间:2010-04-27 19:14:27

标签: c++ qt drag-and-drop desktop directory

我用Qt 4.x编写了一个用C ++编写的小文件传输应用程序...它登录到服务器,向用户显示服务器上可用的文件列表,并允许用户上传或下载文件

这一切都很好;您甚至可以从桌面(或从打开的文件夹)拖入文件,当您将文件图标放入server-files-list-view时,删除的文件将上传到服务器。

现在我也请求相反的操作...我的用户希望能够将文件从server-files-list-view拖到桌面上,或者打开到打开的文件夹窗口,并将该文件下载到该位置。

这似乎是一个合理的要求,但我不知道如何实现它。有没有办法让Qt应用程序找到与“drop event”发生位置相对应的目录,当图标被放到桌面上或打开文件夹窗口时?理想情况下,这将是一个基于Qt的平台中立机制,但如果不存在,那么MacOS / X和Windows(XP或更高版本)的平台特定机制就足够了。

有什么想法吗?

3 个答案:

答案 0 :(得分:7)

查看QMimeData及其文档,它有一个虚函数

virtual QVariant retrieveData  ( const QString & mimetype, QVariant::Type type ) const

这意味着你拖到外面就可以相应地实现这个功能

class DeferredMimeData : public QMimeData
{
  DeferredMimeData(QString downloadFilename) : m_filename(downloadFilename)

  virtual QVariant retrieveData (const QString & mimetype, QVariant::Type type) const 
  {
    if (mimetype matches expected && type matches expected)
    {
       perform download with m_filename
    }
  }
}

delayed encoding示例显示了这一原则。

您可能还必须覆盖hasFormatformats以提供相应的类型,application/octet-stream可能是可能让您玩得最多的类型,您可能需要阅读关于windows如何使用mime类型专门处理拖放。

我不知道你将如何提供保存文件的文件名,但你可能不得不进入窗口方面。查看QWindowsMime的来源也可能有所帮助。我可能会采用多步骤流程来获取文件名text/uri-list数据的请求,然后application/octet-stream获取数据请求。

希望这有帮助

答案 1 :(得分:3)

我认为你是以错误的方式解决这个问题。

你不关心掉落的地方,你只知道掉落了。在DropEvent中,将文件下载到临时位置,然后将mime数据设置为下载的内容。当然这可能最终得到硬盘的第二个副本,它将从一开始就是跨平台。您可以使用特定于平台的呼叫对其进行优化。

看一下Dropsite example,了解mime数据如何与其他来源合作......

编辑:

如果你不编写shell扩展(至少对于windows),看起来像双重复制方法是标准。 Filezilla和7zip都这样做,它们返回一个带有临时位置的“text / uri-list”mime类型。这种方式,资源管理器将数据从临时位置复制到真实位置。您的应用程序也可以这样做,创建一个没有数据的临时文件(或只是名称)。使用delayed encoding example,在drop上创建数据。这整个操作非常具有平台特性。在Linux(运行KDE)上,我可以根据mime类型进行拖放。看起来窗口并不灵活。

答案 2 :(得分:2)

您只需实施the drag part即可。您不需要知道丢弃发生的位置,因为接收它的应用程序将处理它并决定存储文件的位置。

你创建了一个QMimeData,不确定哪种类型,但是从我看到的herehere,也许是“application / octet-stream”,你的文件作为QByteArray中的数据或带文件网址的“text / uri-list”。

你创建一个QDrag,并使用它的setMimeData()方法和exec()(不确定选择哪个QT :: DropAction)。

这是一个例子(disclamer:我是用颜色而不是文件做的):

void DraggedWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
        start_pos = event->pos();
}

void DraggedWidget::mouseMoveEvent(QMouseEvent *event)
{    
    if (event->buttons() & Qt::LeftButton) {
        int distance = (event->pos() - start_pos).manhattanLength();
        if (distance >= QApplication::startDragDistance())
        {
            /* Drag */
            QMimeData *mime_data = new QMimeData;

            mime_data->setData( ... );

            QDrag *drag = new QDrag(this);
            drag->setMimeData(mime_data);
            drag->exec(Qt::CopyAction);
        }
    }
}

对不起,这是非常不完整的,我希望它有所帮助。