Drag and Drop within QTreeWidget



  • Hi all,
    I want to implement a Drag and Drop for QTreeWidget that shows the folder structure with files and folders. I want to drag ONLY FILES and move it into the folder in the same view. When I move over the folder, it should get highlighted for user convenience.

    So I far as from below code, I am able to get the QTreeWidgetItem information for 1 selected file during drag and drop using QDatastream. I m sure the file is getting dragged and dropped properly over the folder.

    However, I have to do with multiple files which I suppose I have to do with QList.
    I am able to get ithe item information on mouse hover. The issues I am facing is I am not getting the highlighted folder on hover. The stylesheet is getting applied after Drop Event occurs. And I want to highlight only when hovering the folder.

    Need help.

    My Code below here:

    @#include <QtGui>
    #include "cloudview.h"

    CloudView::CloudView(QWidget *parent) :
    QTreeWidget(parent)
    {
    setAcceptDrops(true);
    }

    void CloudView::mousePressEvent(QMouseEvent *event)
    {
    qDebug() << "CloudView - MousePressEvent";
    if (event->button() == Qt::LeftButton) {
    startPos = event->pos();
    }

    QTreeWidget::mousePressEvent(event);
    

    }

    void CloudView::mouseMoveEvent(QMouseEvent *event)
    {
    if (event->buttons() & Qt::LeftButton) {
    int distance = (event->pos() - startPos).manhattanLength();
    if (distance >= QApplication::startDragDistance())
    performDrag();
    }

    QTreeWidget::mouseMoveEvent(event);
    

    }

    void CloudView::dragEnterEvent(QDragEnterEvent *event)
    {
    qDebug() << "CloudView - DragEnterEvent";
    CloudView *source = qobject_cast<CloudView *>(event->source());
    if (source) {
    if (event->mimeData()->hasFormat("file/x-temp-files")) {
    event->setDropAction(Qt::MoveAction);
    event->accept();
    }
    else
    event->ignore();
    }
    }

    void CloudView::dragMoveEvent(QDragMoveEvent *event)
    {
    qDebug() << "CloudView - DragMoveEvent";
    CloudView *source = qobject_cast<CloudView *>(event->source());
    if (source) {
    if(event->mimeData()->hasFormat("file/x-temp-files")) {
    QTreeWidgetItem *item = itemAt(event->pos());
    if(item) {
    qDebug() << "itemat: " << item->text(0);
    source->setStyleSheet(QString::fromUtf8("QTreeView::item:hover {\n"
    "background-color: rgb(123, 45, 67);\n"
    "}"));
    }
    else {
    //item->setBackgroundColor(0, QColor(Qt::blue));
    }
    event->setDropAction(Qt::MoveAction);
    event->accept();
    }
    else
    event->ignore();
    }
    }

    void CloudView::dropEvent(QDropEvent *event)
    {
    qDebug() << "CloudView - DropEvent";

    CloudView *source = qobject_cast<CloudView *> (event->source());
    if (source) {
        if (event->mimeData()->hasFormat("file/x-temp-files")) {
            QByteArray appData = event->mimeData()->data("file/x-temp-files");
            QDataStream dataStream(&appData, QIODevice::ReadOnly);
            QTreeWidgetItem item;
            QString str;
            dataStream >> str >> item;
            qDebug() << "str: " << str << "item: " << item.text(0);
    
            //copy item here - to write function
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
        else
            event->ignore();
    }
    

    }

    void CloudView::dragLeaveEvent(QDragLeaveEvent *event)
    {

    }

    void CloudView::performDrag()
    {
    qDebug() << "CloudView - performDrag";
    QTreeWidgetItem *item = currentItem();

    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    
    if (item) {
        dataStream << item->text(0) << *item;
    
        QMimeData *mimeData = new QMimeData;
        mimeData->setData("file/x-temp-files", itemData);
        mimeData->setText(item->text(0));
    
        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(QPixmap(":/Images/edit_copy.png"));
        drag->exec&#40;Qt::MoveAction&#41;;
    }
    

    }

    @



  • I partially solved this issue .

    1. QTreeWidgetItem setData() - can assign data to item. I use this to assign item whether it is a file or folder
      @ if (!link.isDir())
      item->setData(0, Qt::UserRole, QString("file"));
      else
      item->setData(0, Qt::UserRole, QString("folder"));@

    2. In Drag Move Event
      @if(item->data(0, Qt::UserRole).toString()=="folder")
      setCurrentItem(item);
      @

    Now this is solved just for 1 item. I want to use QList with QDataStream when there are multiple selections. I have the following code in performDrag() function;

    @
    QList<QTreeWidgetItem *> items = selectedItems();

    foreach(QTreeWidgetItem* item, items) {
    dataStream << item;
    }
    @

    But how would I get value from datastream at the other end?


  • Moderators

    If you are going to perform drag and drop inside the same widget then just keep a public QStringList and add all the paths into this list before drag has started and on dropevent access this list, parse it and do whatever operations you want to perform. No need to use QDataStream


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.