DropEvent called after window is closed



  • I am implementing simple drag and drop as:

    DragDrop.h

    @#ifndef DRAGDROP_H
    #define DRAGDROP_H

    #include <QWidget>
    #include <QLabel>
    #include <QMouseEvent>
    #include <QPoint>

    class DragDrop : public QWidget
    {

    public:
    DragDrop(QWidget *parent);
    ~DragDrop();

    private:
    QLabel *lblMovable;
    QLabel *lblFixed;
    QPoint dragStartPos;

    protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dragMoveEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    };

    #endif // DRAGDROP_H
    @

    DragDrop.cpp

    @#include "DragDrop.h"

    #include <QApplication>
    #include <QBoxLayout>
    #include <QDrag>
    #include <QMimeData>
    #include <iostream>

    DragDrop::DragDrop(QWidget *parent): QWidget(parent)
    {
    lblMovable = new QLabel("Movable", this);
    lblFixed = new QLabel("Fixed", this);
    lblMovable->move(100, 100);

    this->setAcceptDrops(true);
    

    }

    DragDrop::~DragDrop()
    {
    delete lblMovable;
    delete lblFixed;
    }

    void DragDrop::mousePressEvent(QMouseEvent *event)
    {
    if (event->button() == Qt::LeftButton) {
    dragStartPos = event->pos();
    }
    }

    void DragDrop::mouseMoveEvent(QMouseEvent *event)
    {
    if (!(event->buttons() && Qt::LeftButton)) {
    return;
    }
    if ((event->pos() - dragStartPos).manhattanLength() < QApplication::startDragDistance()) {
    return;
    }
    if (lblMovable->geometry().contains(event->pos())) {
    QDrag *drag = new QDrag(this);
    QMimeData *mimeData = new QMimeData();
    mimeData->setText(lblMovable->text());
    drag->setMimeData(mimeData);
    Qt::DropAction dropAction = drag->exec();
    }
    }

    void DragDrop::dragEnterEvent(QDragEnterEvent *event)
    {
    if (event->mimeData()->hasText()) {
    event->accept();
    }
    }

    void DragDrop::dragMoveEvent(QDragEnterEvent *event)
    {
    if (event->mimeData()->hasText()) {
    event->accept();
    }
    }

    void DragDrop::dropEvent(QDropEvent *event)
    {
    std::cout << "DROP EVENT BEGIN\n";
    if (event->mimeData()->hasText()) {
    QLabel *lbl = new QLabel(this);
    lbl->setText(event->mimeData()->text());
    lbl->move(event->pos());
    event->accept();
    }
    std::cout << "DROP EVENT START\n";
    }

    int main(int argc, char *argv[])
    {
    QApplication *app = new QApplication(argc, argv);
    DragDrop *dd = new DragDrop(0);
    dd->show();
    return app->exec();
    }
    @

    Here is what this code does:

    1. Create a window with two labels: "fixed" and "movable". "movable" support drag drop while "fixed" doesn't.

    2. Window accepts are drop event which has text data.

    3. dragEnterEvent(), dragMoveEvent() and dropEvent() accept the event if it has text data. In dropEvent() I create the label on window where text is dropped.

    4. In mouseMoveEvent() I start a drag on label "movable"

    Problem is for the function dropEvent() is called after I click close for window. This I see because corresponding output to cout is printed that way.


  • Moderators

    std::cout is a very bad way to debug because it is buffered and is sent to your output when the stream is flushed. In your case this is when the app closes, hence the illusion that the "x" triggers event, which it is actually not. If you want to see the output right away you need to flush the stream either via direct std::cout.flush() or std::cout << std::endl (which calls flush internally). you can also use qDebug(), which does not have this problem.

    There are other problems with your code though. You shouldn't explicitly delete lblMovable and lblFixed, since you construct them with a parent (this). They will be automatically deleted when the parent is destroyed. That's how Qt works.

    Other thing is this:
    @
    if (!(event->buttons() && Qt::LeftButton))
    @
    This will always be false since you used a boolean operator(&&) when you probably meant the bit 'and' operator(&), that is used for testing flags like those.

    You should probably also delete the drag object at some point (via QObject::deleteLater()). Maybe in the drop event? It is not leaking, because you created it with a parent(this), which, as previously, will be destroyed with that parent, but each new drag will construct new such object and eventually will eat up some memory that it doesn't have to.



  • Thanks for the reply. It solved the problem ans additional Qt tips are very welcome :)



  • The thing I was missing was @@lbl->show()@@ in dropEvent() to show the created label.


Log in to reply
 

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