鍍金池/ 教程/ C/ 拖放技術(shù)之一
Qt 容器和算法拾遺
自定義 model 之一
反走樣
Hello, world!
Qt 容器類之關(guān)聯(lián)存儲容器
QStringListModel
拖放技術(shù)之一
狀態(tài)欄
QTreeWidget
拖放技術(shù)之二
通用算法
event()
Qt 學(xué)習(xí)之路(18): Qt 標(biāo)準(zhǔn)對話框之 QInputDialog
Qt 容器類之遍歷器和隱式數(shù)據(jù)共享
QListWidget
Meta-Object 系統(tǒng)
事件接收與忽略
Qt 學(xué)習(xí)之路(tip): parent 參數(shù)
Qt 標(biāo)準(zhǔn)對話框之 QColorDialog
QPainter(續(xù))
國際化(下)
漸變填充
自定義委托
創(chuàng)建 shared library
model-view 架構(gòu)
Graphics View Framework
自定義拖放數(shù)據(jù)對象
QSortFilterProxyModel
國際化(上)
組件布局
自定義 Model 之三
事件過濾器
QDirModel
Hello, world!(續(xù))
Qt 標(biāo)準(zhǔn)對話框之 QFileDialog
自定義 model 之二
深入了解信號槽
坐標(biāo)變換
剪貼板操作
QTableWidget
QByteArray 和 QVariant
創(chuàng)建一個(gè)對話框(下)
Qt 學(xué)習(xí)之路(32): 一個(gè)簡易畫板的實(shí)現(xiàn)(Graphics View)
文本文件讀寫
自定義事件
編寫跨平臺的程序
MainWindow
初探信號槽
Qt 學(xué)習(xí)之路(17): Qt 標(biāo)準(zhǔn)對話框之 QMessageBox
繪圖設(shè)備
菜單和工具條(續(xù))
二進(jìn)制文件讀寫
QString
事件(event)
菜單和工具條
QPainter
Qt 容器類之順序存儲容器
進(jìn)程間交互
API 文檔的使用
創(chuàng)建一個(gè)對話框(上)
一個(gè)簡易畫板的實(shí)現(xiàn)(QWidget)

拖放技術(shù)之一

拖放 Drag and Drop,有時(shí)又被稱為 DnD,是現(xiàn)代軟件開發(fā)中必不可少的一項(xiàng)技術(shù)。它提供了一種能夠在應(yīng)用程序內(nèi)部甚至是應(yīng)用程序之間進(jìn)行信息交換的機(jī)制,并且,操作系統(tǒng)與應(yīng)用程序之間進(jìn)行剪貼板的內(nèi)容交換,也可以被認(rèn)為是 DnD 的一部分。

DnD 其實(shí)是由兩部分組成的:Drag 和 Drop。Drag 是將被拖放對象“拖動”,Drop 是將被拖放對象“放下”,前者一般是一個(gè)按下鼠標(biāo)的過程,而后者則是一個(gè)松開鼠標(biāo)的過程,這兩者之間鼠標(biāo)一直是被按下的。當(dāng)然,這只是一種通常的情況,其他情況還是要看應(yīng)用程序的具體實(shí)現(xiàn)。對于 Qt 而言,widget 既可以作為 drag 對象,也可以作為 drop 對象,或者二者都是。

下面的一個(gè)例子來自 C++ GUI Programming with Qt 4, 2nd Edition。在這個(gè)例子中,我們創(chuàng)建一個(gè)程序,可以將系統(tǒng)中的文本文件拖放過來,然后在窗口中讀取內(nèi)容。

mainwindow.h


#ifndef MAINWINDOW_H  
#define MAINWINDOW_H  

#include <QtGui>  

class MainWindow : public QMainWindow  
{  
    Q_OBJECT  

public:  
    MainWindow(QWidget *parent = 0);  
    ~MainWindow();  

protected:  
    void dragEnterEvent(QDragEnterEvent *event);  
    void dropEvent(QDropEvent *event);  

private:  
    bool readFile(const QString &fileName);  
    QTextEdit *textEdit;  
};  

#endif // MAINWINDOW_H 

mainwindow.cpp


#include "mainwindow.h"  

MainWindow::MainWindow(QWidget *parent)  
    : QMainWindow(parent)  
{  
    textEdit = new QTextEdit;  
    setCentralWidget(textEdit);  

    textEdit->setAcceptDrops(false);  
    setAcceptDrops(true);  

    setWindowTitle(tr("Text Editor"));  
}  

MainWindow::~MainWindow()  
{  
}  

void MainWindow::dragEnterEvent(QDragEnterEvent *event)  
{  
    if (event->mimeData()->hasFormat("text/uri-list")) {  
        event->acceptProposedAction();  
    }  
}  

void MainWindow::dropEvent(QDropEvent *event)  
{  
    QList<QUrl> urls = event->mimeData()->urls();  
    if (urls.isEmpty()) {  
        return;  
    }  

    QString fileName = urls.first().toLocalFile();  
    if (fileName.isEmpty()) {  
        return;  
    }  

    if (readFile(fileName)) {  
        setWindowTitle(tr("%1 - %2").arg(fileName, tr("Drag File")));  
    }  
}  

bool MainWindow::readFile(const QString &fileName)  
{  
    bool r = false;  
    QFile file(fileName);  
    QTextStream in(&file);  
    QString content;  
    if(file.open(QIODevice::ReadOnly)) {  
        in >> content;  
        r = true;  
    }  
    textEdit->setText(content);  
    return r;  
} 

main.cpp


#include <QtGui/QApplication>  
#include "mainwindow.h"  

int main(int argc, char *argv[])  
{  
    QApplication a(argc, argv);  
    MainWindow w;  
    w.show();  
    return a.exec();  
}

這里的代碼并不是很復(fù)雜。在 MainWindow 中,一個(gè) QTextEdit 作為窗口中間的 widget。這個(gè)類中有兩個(gè) protected 的函數(shù):dragEnterEvent() 和 dropEvent(),這兩個(gè)函數(shù)都是繼承自 QWidget,看它們的名字就知道這是兩個(gè)事件,而不僅僅是 signal。

在構(gòu)造函數(shù)中,我們創(chuàng)建了 QTextEdit 的對象。默認(rèn)情況下,QTextEdit 可以接受從其他的應(yīng)用程序拖放過來的文本類型的信息。如果用戶把一個(gè)文件拖到這里面,那么就會把文件名插入到文本的當(dāng)前位置。但是我們希望讓 MainWindow 讀取文件內(nèi)容,而不僅僅是插入文件名,所以我們在 MainWindow 中對 drop 事件進(jìn)行了處理,因此要把 QTextEdit 的 setAcceptDrops()函數(shù)置為 false,并且把MainWindow 的 setAcceptDrops()置為 true,以便讓 MainWindow 對 drop 事件進(jìn)行處理。 當(dāng)用戶將對象拖動到組件上面時(shí),dragEnterEvent()函數(shù)會被回調(diào)。如果我們在事件處理代碼中調(diào)用 acceptProposeAction() 函數(shù),我們就可以向用戶暗示,你可以將拖動的對象放在這個(gè)組件上。默認(rèn)情況下,組件是不會接受拖放的。如果我們調(diào)用了這樣的函數(shù),那么 Qt 會自動地以光標(biāo)來提示用戶是否可以將對象放在組件上。在這里,我們希望告訴用戶,窗口可以接受拖放。因此,我們首先檢查拖放的MIME 類型。MIME 類型為 text/uri-list 通常用來描述一個(gè) URI 的列表。這些 URI 可以是文件名,可以是 URL或者其他的資源描述符。MIME 類型由 Internet Assigned Numbers Authority (IANA) 定義,Qt 的拖放事件使用MIME類型來判斷拖放對象的類型。關(guān)于 MIME 類型的詳細(xì)信息,請參考 http://www.iana.org/assignments/media-types/.

當(dāng)用戶將對象釋放到組件上面時(shí),dropEvent() 函數(shù)會被回調(diào)。我們使用 QMimeData::urls()來或者 QUrl 的一個(gè) list。通常,這種拖動應(yīng)該只用一個(gè)文件,但是也不排除多個(gè)文件一起拖動。因此我們需要檢查這個(gè) list 是否為空,如果不為空,則取出第一個(gè)。如果不成立,則立即返回。最后我們調(diào)用 readFile() 函數(shù)讀取文件內(nèi)容。關(guān)于讀取操作我們會在以后的章節(jié)中詳細(xì)說明,這里不再贅述。 好了,至此我們的小程序就解釋完畢了,運(yùn)行一下看看效果吧!

對于拖動和脫離,Qt 也提供了類似的函數(shù):dragMoveEvent() 和 dragLeaveEvent(),不過對于大部分應(yīng)用而言,這兩個(gè)函數(shù)的使用率要小得多。

本文出自 “豆子空間” 博客,請務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/193918