2010-04-27 62 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

相關問題