拖放 Drag and Drop,有時又被稱為 DnD,是現代軟件開發中必不可少的一項技術。它提供了一種能夠在應用程序內部甚至是應用程序之間進行信息交換的機制,並且,操作系統與應用程序之間進行剪貼板的內容交換,也可以被認為是 DnD 的一部分。 DnD 其實是由兩部分組成的:Drag 和 Drop。Drag 是將被拖放對象“拖動”,Drop 是將被拖放對象“放下”,前者一般是一個按下鼠標的過程,而後者則是一個松開鼠標的過程,這兩者之間鼠標一直是被按下的。當然,這只是一種通常的情況,其他情況還是要看應用程序的具體實現。對於 Qt 而言,widget既可以作為 drag 對象,也可以作為 drop 對象,或者二者都是。 下面的一個例子來自 C++ GUI Programming with Qt 4, 2nd Edition。在這個例子中,我們創建一個程序,可以將系統中的文本文件拖放過來,然後在窗口中讀取內容。 mainwindow.h
mainwindow.cpp
- #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
main.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;
- }
這裡的代碼並不是很復雜。在MainWindow中,一個QTextEdit作為窗口中間的widget。這個類中有兩個protected的函數:dragEnterEvent() 和 dropEvent(),這兩個函數都是繼承自 QWidget,看它們的名字就知道這是兩個事件,而不僅僅是signal。 在構造函數中,我們創建了 QTextEdit 的對象。默認情況下,QTextEdit 可以接受從其他的應用程序拖放過來的文本類型的信息。如果用戶把一個文件拖到這裡面,那麼就會把文件名插入到文本的當前位置。但是我們希望讓MainWindow 讀取文件內容,而不僅僅是插入文件名,所以我們在MainWindow中對 drop 事件進行了處理,因此要把QTextEdit的setAcceptDrops()函數置為false,並且把MainWindow的setAcceptDrops()置為true,以便讓MainWindow對 drop 事件進行處理。 當用戶將對象拖動到組件上面時,dragEnterEvent()函數會被回調。如果我們在事件處理代碼中調用 acceptProposeAction() 函數,我們就可以向用戶暗示,你可以將拖動的對象放在這個組件上。默認情況下,組件是不會接受拖放的。如果我們調用了這樣的函數,那麼Qt會自動地以光標來提示用戶是否可以將對象放在組件上。在這裡,我們希望告訴用戶,窗口可以接受拖放。因此,我們首先檢查拖放的MIME類型。MIME類型為 text/uri-list 通常用來描述一個 URI 的列表。這些 URI 可以是文件名,可以是 URL或者其他的資源描述符。MIME類型由 Internet Assigned Numbers Authority (IANA) 定義,Qt 的拖放事件使用MIME類型來判斷拖放對象的類型。關於 MIME類型的詳細信息,請參考 http://www.iana.org/assignments/media-types/. 當用戶將對象釋放到組件上面時,dropEvent() 函數會被回調。我們使用 QMimeData::urls()來或者 QUrl 的一個list。通常,這種拖動應該只用一個文件,但是也不排除多個文件一起拖動。因此我們需要檢查這個list是否為空,如果不為空,則取出第一個。如果不成立,則立即返回。最後我們調用 readFile() 函數讀取文件內容。關於讀取操作我們會在以後的章節中詳細說明,這裡不再贅述。 好了,至此我們的小程序就解釋完畢了,運行一下看看效果吧! 對於拖動和脫離,Qt 也提供了類似的函數:dragMoveEvent() 和 dragLeaveEvent(),不過對於大部分應用而言,這兩個函數的使用率要小得多。
- #include <QtGui/QApplication>
- #include "mainwindow.h"
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- MainWindow w;
- w.show();
- return a.exec();
- }
本文出自 “豆子空間” 博客,請務必保留此出處http://devbean.blog.51cto.com/448512/280052