拖放(Drag and Drop)

拖放(Drag and Drop)由拖動和釋放兩部分組成,拖動是將被拖放對象進行移動,釋放是將被拖放對象放下,兩者進行了信息的交換,我們使用的剪貼板的剪下貼上,也可說是拖放的一部分。

有些元件預設接受拖放行為,像我們可直接將文字拖曳至QLineEdit,這會將拖曳的文字置放在此處,不過大部分元件或應用程式要能支援拖放功能,必須使用setAcceptDrops()函式,設定元件接受拖放動作。

在拖放動作發生時,會有相對應的QDragEnterEvent、QDragMoveEvent、QDragLeaveEvent與QDropEvent等事件發生,通常重載dragEnterEvent()和dropEvent(),來處理相對應的拖放事件。


範例為一簡單的主窗口和一個標籤,當我們將圖檔拖放至窗口上,QLabel會自動載入圖片並顯示出來。

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
private:
    QLabel *label;
protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);
};

#endif 

widget.cpp

#include "widget.h"
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    setWindowTitle(tr("拖放事件"));
    label = new QLabel(this);
    label->setText(tr("請將圖檔拖在此處"));
    label->setGeometry(20,20,200,200);      //設定位置大小
    label->setAlignment(Qt::AlignCenter);   //label文字置中
    setAcceptDrops(true);                   //設定為可拖放物件
}

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

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

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

    QPixmap pixmap(fileName);
    label->setPixmap(pixmap);
    label->resize(pixmap.width(), pixmap.height());
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

Drag and Drop

Drag and Drop


  • setAcceptDrops(true)表示支援拖放行為,反之false表示不支援。
  • acceptProposeAction()目的在向使用者暗示,可以將拖動的對象放在這個組件上,如果我們調用了這個函數,那麼Qt會自動以光標樣式的變化來提示用戶是否可以將對象放在組件上。但是我們僅接受某一種類型的文件,而不是所以文件,如果先判斷使用者拖放的檔案,如果是一個text/uri-list數據(即文件名),我們便接受拖放動作。
  • 當用戶將對象釋放到組件上面時,系統回呼dropEvent()函數。我們使用QMimeData::urls()來獲得拖動檔案文件的列表。先檢查這個列表是否為空,如果為空就返回,可能一次拖曳一個或多個,不過我們這邊只取第一個檔案名,最後將label設定為和圖檔大小相同。