拖放是應用程序內或者應用程序之間數據傳遞的一種方式。通常是提供數據的復制和移動。拖放主要包括拖動和放下。有些窗口可能只需要提供拖動功能,有些窗口可能只需要放下,有些窗口可能兩者功能都需要具備。Qt的一些控件不需要進行任何設置,就具備拖放功能,比如QLineEdit、QTextEdit。
QLineEdit可以接受拖動過來的字符串,而QTextEdit可以接受拖動的字符串以及拖動文件的路徑。所需要做的就是創建一個對象,然後顯示,如下:
QLineEdit lineEdit;
lineEdit.show();
QTextEdit textEdit;
textEdit.show();
QLineEdit接受文字拖放,測試效果:
QTextEdit接受文件拖放,顯示文件的路徑,支持多個文件一起拖放,測試效果:
QWidget實現拖放,需要設置接受拖放,
setAcceptDrops(true);
並實現下面事件:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
如果我們只需要QWidget接受放下,那麼就不需要實現:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
這兩個事件主要是,當我們需要QWidget實現拖動時才需要的。
QApplication提供了兩種方式來啟動一個拖動操作:
QApplication::startDragDistance():通過鼠標移動的距離來判斷是否啟動拖放,默認是10個像素點。但也可以通過static void setStartDragDistance(int l);來進行自定義開始拖放的距離。
QApplication::startDragTime():通過鼠標點擊的時長來判斷是否啟動拖放,默認是500ms。也可以通過static void setStartDragTime(int ms);來自定義按壓時長。
為了實現拖放,我們需要在mousePressEvent內記錄鼠標按下的坐標點或者時間點,然後在mouseMoveEvent判斷鼠標移動的距離或者按壓時間是否滿足拖放要求,從而啟動拖放。
執行拖放操作,我們需要創建一個QDrag對象,此對象包含QMimeData,這裡保存著我們需要拖動的數據。
示例:
void QDragDrop::mousePressEvent(QMouseEvent *event)
{
__super::mousePressEvent(event);
mStartPoint = event->pos();//起點
}
void QDragDrop::mouseMoveEvent(QMouseEvent *event)
{
__super::mouseMoveEvent(event);
if ((event->pos() - mStartPoint).manhattanLength() > QApplication::startDragDistance())//判斷是否執行拖動
{
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QByteArray byteArray;//存儲數據
QDataStream stream(&byteArray,QIODevice::WriteOnly);//流,寫數據
stream << QImage("C:\\Users\\dlp\\Desktop\\2.png");//讀取一個圖片的數據
mimeData->setData("MyImage", byteArray);//設置數據
drag->setMimeData(mimeData);//設置數據
drag->exec(Qt::MoveAction);//執行拖動
delete drag;
}
}
上述示例,讀取了一個圖片的數據保存在QMimeData裡面,作為要傳遞的數據。並且設置了自定義格式"MyImage"。
效果如下:
示例代碼如下:
#ifndef QDRAGDROP_H
#define QDRAGDROP_H
#include
#include
#include
class QDragDrop : public QWidget
{
Q_OBJECT
public:
QDragDrop(QWidget *parent = 0);
~QDragDrop();
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint mStartPoint;
QHBoxLayout *m_HBox;
};
#endif // QDRAGDROP_H
#include "qdragdrop.h"
#include
#include
#include
#include
QDragDrop::QDragDrop(QWidget *parent)
: QWidget(parent)
{
mStartPoint = QPoint(0, 0);
m_HBox = new QHBoxLayout(this);
setAcceptDrops(true);
setWindowTitle("QWidget");
}
QDragDrop::~QDragDrop()
{
}
void QDragDrop::mousePressEvent(QMouseEvent *event)
{
__super::mousePressEvent(event);
mStartPoint = event->pos();//起點
}
void QDragDrop::mouseMoveEvent(QMouseEvent *event)
{
__super::mouseMoveEvent(event);
if ((event->pos() - mStartPoint).manhattanLength() > QApplication::startDragDistance())//判斷是否執行拖動
{
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QByteArray byteArray;//存儲數據
QDataStream stream(&byteArray,QIODevice::WriteOnly);//流,寫數據
stream << QImage("C:\\Users\\dlp\\Desktop\\2.png");//讀取一個圖片的數據
mimeData->setData("MyImage", byteArray);//設置數據
drag->setMimeData(mimeData);//設置數據
drag->exec(Qt::MoveAction);//執行拖動
delete drag;
}
}
void QDragDrop::dragEnterEvent(QDragEnterEvent *event)
{
__super::dragEnterEvent(event);
if (event->mimeData()->hasFormat("MyImage"))
event->acceptProposedAction();
}
void QDragDrop::dragMoveEvent(QDragMoveEvent *event)
{
__super::dragMoveEvent(event);
if (event->mimeData()->hasFormat("MyImage"))
event->acceptProposedAction();
}
void QDragDrop::dropEvent(QDropEvent *event)
{
__super::dropEvent(event);
if (event->mimeData()->hasFormat("MyImage"))
{
QByteArray byteArray = event->mimeData()->data("MyImage");//取數據
QDataStream stream(&byteArray, QIODevice::ReadOnly);//流,讀數據
QImage image;
stream >> image;
QLabel *pLabel = new QLabel(this);
pLabel->setPixmap(QPixmap::fromImage(image));
m_HBox->addWidget(pLabel);
}
}
如果我們只需要接收放下,不需要拖動的話,那麼就不需要上述示例中的兩個鼠標事件。下面實現了一個拖動圖片到窗口並使用QLabel顯示出來的示例:
效果:
示例代碼:
#ifndef QSHOWIMAGE_H
#define QSHOWIMAGE_H
#include
#include
#include
#include
class QShowImage : public QWidget
{
Q_OBJECT
public:
QShowImage(QWidget *parent = 0);
~QShowImage();
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
private:
QHBoxLayout *mLayout;
};
#endif // QSHOWIMAGE_H
#include "QShowImage.h"
#include
#include
QShowImage::QShowImage(QWidget *parent)
: QWidget(parent)
{
mLayout = new QHBoxLayout(this);
setAcceptDrops(true);
setWindowTitle("ShowImage");
}
QShowImage::~QShowImage()
{
}
void QShowImage::dragEnterEvent(QDragEnterEvent *event)
{
__super::dragEnterEvent(event);
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void QShowImage::dropEvent(QDropEvent *event)
{
__super::dropEvent(event);
if (event->mimeData()->hasUrls())
{
QList urls = event->mimeData()->urls();
for each (QUrl url in urls)
{
QLabel *pLabel = new QLabel(this);
QImage image(url.toString().mid(8));
pLabel->setPixmap(QPixmap::fromImage(image));
mLayout->addWidget(pLabel);
}
}
}
對於QListWidget來說,拖放並不像上面那樣復雜,僅僅設置一下,就可以實現QListWidgetItem的拖動:
setDragEnabled(true);
實現代碼:
QListWidget qlistWidget;
QStringList strList = { "Item1", "Item2", "Item3", "Item4", "Item5" };
qlistWidget.addItems(strList);
qlistWidget.setViewMode(QListView::IconMode);
qlistWidget.setDragEnabled(true);
qlistWidget.show();
但是上述只是移動了位置,Item的具體索引並沒有發生改變。而且如果我們需要實現其他拖放功能,並不能滿足我們的需求。那麼我們就需要重新實現拖放事件,來自定義我們自己需要實現的功能。我實現了如何拖動Item,然後再添加一個Item的功能,兩個QListWidgetItem並沒有什麼關聯,只是為了展示如何實現。
效果:
示例代碼:
#ifndef LISTWIDGET_H
#define LISTWIDGET_H
#include
#include
class ListWidget : public QListWidget
{
Q_OBJECT
public:
ListWidget(QWidget *parent = 0);
~ListWidget();
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
};
#endif // LISTWIDGET_H
#include "ListWidget.h"
#include
#include
#include
ListWidget::ListWidget(QWidget *parent)
: QListWidget(parent)
{
QStringList strList = { "Item1", "Item2", "Item3", "Item4", "Item5" };
addItems(strList);
setViewMode(QListView::IconMode);
setDragEnabled(true);
setWindowTitle("QListWidget");
}
ListWidget::~ListWidget()
{
}
void ListWidget::dragEnterEvent(QDragEnterEvent *event)
{
__super::dragEnterEvent(event);
ListWidget *pList = qobject_cast(event->source());//拖動的源對象
if (pList && pList == this)
{
event->setDropAction(Qt::DropAction::CopyAction);//設置拖動動作,影響鼠標光標
event->accept();
}
}
void ListWidget::dragMoveEvent(QDragMoveEvent *event)
{
__super::dragMoveEvent(event);
ListWidget *pList = qobject_cast(event->source());//拖動的源對象
if (pList && pList == this)
{
event->setDropAction(Qt::DropAction::CopyAction);//設置拖動動作,影響鼠標光標
event->accept();
}
}
void ListWidget::dropEvent(QDropEvent *event)
{
__super::dropEvent(event);
ListWidget *pList = qobject_cast(event->source());//拖動的源對象
if (pList && pList == this)
{
QListWidgetItem *pItem = new QListWidgetItem(this);//執行釋放後,要做的事情
pItem->setText(QString("Item").append(QString::number(count())));
addItem(pItem);
}
}