Video: Drag and Drop (5 MB)
Valuable drag and drop examples for beginner are not present in Qt distribution, so let's have a closer look at it.
Please read customing widgets and have a look at Qt documentation about drag&drop before reading this.
Adjust the form from previous tutorial, place QLineEdit, QTreeWidget and QListWidget on it.
Promote QLineEdit, QTreeWidget and QListWidget to promote widgets and create appropriate .h and .cpp files like we did in previous tutorial.
Make sure acceptDrops property is set to true on each of them.
We will implement drop capability to QLineEdit (now myLineEdit). When file is dropped (but not directory), path will appear in myLineEdit.
Define the following methods in mylineedit.h
void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event);
and implement in mylineedit.cpp
void myLineEdit::dragEnterEvent(QDragEnterEvent *event) { // accept just text/uri-list mime format if (event->mimeData()->hasFormat("text/uri-list")) { event->acceptProposedAction(); } } void myLineEdit::dropEvent(QDropEvent *event) { QList<QUrl> urlList; QString fName; QFileInfo info; if (event->mimeData()->hasUrls()) { urlList = event->mimeData()->urls(); // returns list of QUrls // if just text was dropped, urlList is empty (size == 0) if ( urlList.size() > 0) // if at least one QUrl is present in list { fName = urlList[0].toLocalFile(); // convert first QUrl to local path info.setFile( fName ); // information about file if ( info.isFile() ) setText( fName ); // if is file, setText } } event->acceptProposedAction(); }
Recompile and try to drop file (from explorer) into customized QLineEdit.
You may think we will do the same as with QLineEdit, but setup is little different.
If you look at Protected Functions of QTreeWidget you'll see some virtual functions responsible for drag/drop.
To actually implement drop on QTreeWidget, define following methods in mytreewidget.h
virtual bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action); QStringList mimeTypes() const; Qt::DropActions supportedDropActions () const;
mytreewidget.cpp
bool myTreeWidget::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) { QList<QUrl> urlList; QTreeWidgetItem *item; urlList = data->urls(); // retrieve list of urls foreach(QUrl url, urlList) // iterate over list { // make new QTreeWidgetItem and set its text // if parent is null - add top level item (this parent) if (parent == NULL) item = new QTreeWidgetItem(this); else // else add QTreeWidgetItem with parent and expand parent { item = new QTreeWidgetItem(parent); parent->setExpanded( true ); } // set item text item->setText( 0, url.toLocalFile() ); } return true; } QStringList myTreeWidget::mimeTypes () const { QStringList qstrList; // list of accepted mime types for drop qstrList.append("text/uri-list"); return qstrList; } Qt::DropActions myTreeWidget::supportedDropActions () const { // returns what actions are supported when dropping return Qt::CopyAction | Qt::MoveAction; }
DragDropOverwriteMode property can be enabled to enhance visual effect when dropping.
This is pretty much same as with QTreeWidget. The only difference is different parameters list in function dropMimeData.
mylistwidget.h
virtual bool dropMimeData(int index, const QMimeData *data, Qt::DropAction action); QStringList mimeTypes() const; Qt::DropActions supportedDropActions () const;
mylistwidget.cpp
bool myListWidget::dropMimeData(int index, const QMimeData *data, Qt::DropAction action) { QList <QUrl> urlList; QListWidgetItem *item; QFileInfo info; QString fName; urlList = data->urls(); // retrieve list of urls foreach(QUrl url, urlList) // iterate over list { fName = url.toLocalFile(); info.setFile( fName ); item = new QListWidgetItem(info.fileName()); insertItem(index, item); ++index; // increment index to preserve drop order } return true; } QStringList myListWidget::mimeTypes () const { // same as with QTreeWidget } Qt::DropActions myListWidget::supportedDropActions () const { // same as with QTreeWidget }
To implement drag operation, override mouseMoveEvent(QMouseEvent *event) method.
mylistwidget.h
void mouseMoveEvent(QMouseEvent *event);
mylistwidget.cpp
void myListWidget::mouseMoveEvent(QMouseEvent *event) { // if not left button - return if (!(event->buttons() & Qt::LeftButton)) return; // if no item selected, return (else it would crash) if (currentItem() == NULL) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; // construct list of QUrls // other widgets accept this mime type, we can drop to them QList<QUrl> list; list.append(QUrl(currentItem()->text())); // only QUrl in list will be text of actual item // mime stuff mimeData->setUrls(list); drag->setMimeData(mimeData); // start drag drag->start(Qt::CopyAction | Qt::MoveAction); }
Project ready: drag_and_drop.zip