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
 

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