2010-04-27 273 views
18

我已经写了C++编写的使用Qt 4.x的一个小文件传输应用程序...,在登录到服务器,显示了用户在服务器上的可用文件的列表,并允许用户上传或下载文件。Qt 4.x:如何实现拖放到桌面或文件夹?

这一切工作正常;您甚至可以从桌面(或从打开的文件夹)拖入文件,并且当您将文件图标拖放到服务器文件列表视图中时,被拖放的文件将上传到服务器。

现在我有一个相反的动作要求,以及...我的用户希望能够将文件从服务器的文件列表视图,并到桌面上,或进入打开的文件夹窗口,并将该文件下载到该位置。

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

任何想法?

+0

我试图做到这一点使用Qt 4.2半晌回,并没有找到一种方法,做正确。但也许有人可以想出一个解决方案呢? – BastiBen 2010-04-28 12:36:10

+1

看到我的回应,你不能轻易跨平台去做。例如,除非将文件下载到临时目录,然后让Windows将其复制到正确的位置,否则Windows需要外壳扩展。 – 2010-04-29 14:10:12

+0

@Jeremy Friesner 你能解决这个问题而不会冻结你的gui吗? – atamanroman 2011-11-08 16:13:27

回答

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可能是一个可能让您获得最多的发挥,你可能会就如何窗户读了专门处理阻力和使用MIME下降类型。

我不知道你将如何提供其下保存文件的文件名,但你可能要进入事物的窗户边。查看QWindowsMime的来源可能也有帮助。我可能需要一个多步骤的过程,在这个过程中,您将获得关于文件名的text/uri-list数据的请求,然后获取关于数据的application/octet-stream的请求。

希望这有助于

+0

这看起来像它几乎可以工作,除了我怀疑它会冻结我的应用程序的GUI,直到retrieveData()返回。鉴于下载可能需要很长时间(几分钟或几小时)而不是最佳的。 :/ – 2010-04-28 16:10:27

+1

我会说,这并不排除在单独的线程中下载或通过QCoreApplication :: processEvents()来让GUI处理事件。我必须承认,虽然我试图破解延迟编码示例来存放文件在桌面上并没有太大的成功 – 2010-04-28 20:01:22

+0

单独的线程不会有帮助,因为retrieveData()仍然需要阻止,因为它返回数据的返回值,因此无法返回,直到下载完成。从retrieveData()中调用processEvents()可能可行,但我不会相信它......过去我被这种技术所烧毁。 – 2010-04-29 16:26:16

3

我认为你在错误的道路会有关。

你不在乎降去,你只知道它已被删除。在DropEvent中,将文件下载到临时位置,然后将MIME数据设置为下载的内容。当然,这可能会导致第二次复制到硬盘上,从一开始就会跨平台。您可能可以通过平台特定的呼叫对其进行优化。

看看Dropsite example看到MIME数据从其他来源是如何工作的?

编辑:

它看起来像双拷贝的方法是,如果你不写一个shell标准扩展名(至少适用于Windows)。 Filezilla和7zip都是这样做的,它们会返回一个带有临时位置的“text/uri-list”MIME类型。这样explorer将数据从临时位置复制到真实位置。您的应用程序可以做同样的事情,创建一个没有数据的临时文件(或名称)。使用delayed encoding example,在放置上创建数据。这整个操作是非常平台特定的。在Linux上(运行KDE),我可以根据MIME类型进行拖放。看起来,窗户不那么灵活。

+0

第一个问题是,我没有得到一个DropEvent,因为图标滴到deskt操作(或进入文件夹),并且不会丢弃在我的应用程序窗口中。 第二个问题是,我确实是会需要知道的图标被放弃了,因为这是用户想要的文件出现在目录中。 – 2010-04-27 21:23:40

+0

顺便说一句我看着DropSite例子,它是不相关的,因为它只能用作放置站点,而不能用作拖动源。 – 2010-04-27 21:26:27

+1

请在投票前阅读。该dropsite示例显示如何使用任何来源的MIME类型。您可以启动您的程序,然后放到该程序上以查看列出的MIME类型。 至于第一部分,你让操作系统处理掉落。你提供它的MIME类型和数据,它会把它放在你丢弃它的地方。就像将项目从一个浏览器窗口拖到另一个窗口一样。 请阅读拖放文档以及http://bit.ly/bDooQe – 2010-04-28 00:27:41

2

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

您创建一个QMimeData,不知道哪种类型,但是从我所看到的herehere,也许“应用程序/八位字节流”与您的文件作为一个QByteArray中或“文/ URI列表”的数据与URL到您的文件。

您创建一个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); 
     } 
    } 
} 

对不起这是相当不完整的,我希望它有助于一点点。

+1

问题是,直到下载完成后,文件中的数据才可用,而多GB的下载可能需要一个小时或更长时间。所以我需要知道下降发生的位置,以便我的应用程序可以启动下载线程将数据写入该位置。 AFAICT是一种依赖于拖动时本地存在的数据的系统,对我而言不起作用。 只有在文件可以通过操作系统知道如何下载的协议(例如HTTP?)访问文件时,才可以使用URI。目前该服务器使用专有协议。嗯.... – 2010-04-28 03:20:03