Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

dragEnterEvent from external file issue



  • I have a situation like this: http://imgur.com/a/4BpNv
    I have a sublclass derived from QTableWidget, modified to accept drag'n drop both internal row and external file. When I drag a file from a Window folder to the TableWidget, the dnd animation stop ath the edge of the TableWidget, preventing me to freely move the mouse inside the TableWidget to select the point where I run the drop. This only happens when I drag file directly from Windows folders, while if I drag files from the Qt API QFileDialog::getOpenFileName() dialog the the dnd works as I would like.

    This is the subclass:

    #include <QtGui>
    #include <QDrag>
    #include <QPainter>
    #include <QDropEvent>
    #include <QCursor>
    #include "dtablewidget.h"
    
    DTableWidget::DTableWidget(QWidget *parent) : QTableWidget(parent) {
        //set widget default properties:
    
        viewport()->setAcceptDrops(true); //set accept drop on viewport
        setDragEnabled(true);
        setDragDropOverwriteMode(false); //set drag drop overwrite to false
        setDragDropMode(QAbstractItemView::DragDrop); //enable internal drag drop on tablular dispaly
        setSelectionBehavior(QAbstractItemView::SelectRows); //enable selection of entire row
        setEditTriggers(QAbstractItemView::NoEditTriggers);//preventing editing
        setAlternatingRowColors(true);
        setSelectionBehavior(QAbstractItemView::SelectRows);
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
        setShowGrid(false);
        setAcceptDrops(true);
        setWordWrap(false);
        setStyleSheet("selection-background-color: yellow;"
                      "selection-color: #002041;"
                      "font-size: 75%;"
                      );
    
    }
    
    void DTableWidget::dragEnterEvent(QDragEnterEvent *event) {
        qDebug() << "dragEnterEvent";
        event->accept();
    }
    
    void DTableWidget::dragMoveEvent(QDragMoveEvent *event) {
        qDebug() << "dragMoveEvent";
        if (event->source() != this) {
            QDrag *drag = new QDrag(this);
            QMimeData *mimeData = new QMimeData;
            mimeData->setUrls(event->mimeData()->urls());
            drag->setMimeData(mimeData);
            drag->exec(Qt::LinkAction);
    }
        else {
            event->acceptProposedAction();
            event->setDropAction(Qt::LinkAction);
        }
    }
    
    void DTableWidget::dropEvent(QDropEvent *event) {
        event->acceptProposedAction();
        event->setDropAction(Qt::LinkAction);
        qDebug() << "dropEvent" << event << event->mimeData()->urls().count();
        if (event->mimeData()->urls().count() > 0) {
            emit dropped(event->mimeData());
            qDebug() << "dropEvent" << event->mimeData()->urls().count();
        }
        else {
            QPoint old_coordinates = QPoint(-1,-1);
            if(currentItem() != NULL) //Check if user is not accessing empty cell
            {
                old_coordinates = QPoint(currentItem()->row(), currentItem()->column());
            }
            if(this->itemAt(event->pos().x(), event->pos().y()) != NULL && old_coordinates != QPoint(-1, -1))
            {
                emit moved(old_coordinates.x(), itemAt( event->pos().x(), event->pos().y())->row());
            }
        }
    }
    
    void DTableWidget::dragLeaveEvent(QDragLeaveEvent *event) {
        qDebug() << "dragLeaveEvent";
    }
    
    void DTableWidget::keyPressEvent(QKeyEvent *event) {
        emit keyboard(event);
    }
    
    void DTableWidget::startDrag(Qt::DropActions supportedActions) {
        QModelIndexList indexes = selectedIndexes();
        if (indexes.count() > 0) {
            QMimeData *data = model()->mimeData(indexes);
            if (!data)
                return;
            QDrag *drag = new QDrag(this);
            drag->setMimeData(data);
            Qt::DropAction defaultDropAction = Qt::IgnoreAction;
            if (defaultDropAction != Qt::IgnoreAction && (supportedActions & defaultDropAction))
                defaultDropAction = defaultDropAction;
            else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
                defaultDropAction = Qt::MoveAction;
            drag->exec(defaultDropAction);
        }
    }
    
    

    Can you help me?


  • Moderators

    @UnitScan said in dragEnterEvent from external file issue:

    void DTableWidget::dragMoveEvent

    i stopped reading after i saw your implementation of the dragMoveEvent() becasue its so horribly wrong :)

    Why do you create a new QDrag there?
    When you receive a dragMoveEvent it means that there is already a drag currently happening, otherwise you wouldn't receive the event in the first place.

    Just remove the whole if (event->source() != this) block and it should work.
    If you really have to check if the drag origins from inside your application do event->source(). If it returns a null-pointer the drag comes from outside your application.



  • I created a new QDrag because I wish to change the horrible mouse cursor pixmap that appears during dragMoveEvent, and replace it with a simple Leftarrow, without the preview of the file I'm dragging, with the small symbol of the link at the bottom right of the cursor.

    void DTableWidget::dragMoveEvent(QDragMoveEvent *event) {
    
        qDebug() << "dragMoveEvent";
        if (event->source() != this) {
            QDrag *drag = new QDrag(this);
            QCursor cursor;
            cursor.setShape(Qt::ArrowCursor);
    
            drag->setPixmap(cursor.pixmap());
            this->cursor().setShape(Qt::ArrowCursor);
            drag->setDragCursor(this->cursor().pixmap(),Qt::LinkAction);
            QMimeData *mimeData = new QMimeData;
            mimeData->setUrls(event->mimeData()->urls());
            drag->setMimeData(mimeData);
            drag->exec(Qt::LinkAction);
    }
        else {
    
            event->acceptProposedAction();
            event->setDropAction(Qt::LinkAction);
        }
    }
    

    If there is a better way to do that, what is?


  • Moderators

    @UnitScan said in dragEnterEvent from external file issue:

    event->setDropAction(Qt::LinkAction);

    you mean like you do in the else-block afterwards?
    Basically it's only possible to set the cursor during a drag to 4 states:
    Copy, Move, Link, NoAction. The operating system decides how to show them.

    Thus setting it to a "plain" cursor isn't possible.



  • I don't want a plain cursor, but a dragCursor(Qt::LinkAction). How can I do it?


  • Moderators

    you are already doing it in the else-block (event->setDropAction()) like i already said in my previous post!
    The "drag image" cannot be removed. Not via Qt API at least.



  • I noticed that with Clementine, player made with QT5 libraries, when you drag an external file to the playlist appears only a LeftArrorw with a small square at the bottom right with the "+" symbol, while with me appears, beyond Leftarrow, a gigantic preview of the file I'm dragging and an abnormal word "Link" at the bottom right :'-(
    Changing event->setDropAction(Qt::LinkAction) to event->setDropAction(Qt::CopyAction) replace only the abnormal text label from "Link" to "Copy"


  • Moderators

    @UnitScan
    And you are sure they just use the Qt API for Drag-n-Drop handling?!
    Anyway you can check the source code how they do it.



  • There are other way out of Qt to handle drag'n drop?


  • Moderators

    @UnitScan
    using the native API directly for example

    But again to make sure: On the same machine (same OS) the Clementine player doesn't show the drag image while your application does?



  • @raven-worx Yes. on Windows Clementine shows only the small "+" on the bottom right, while my app show the gigantic file preview and the "Link" text


Log in to reply