简体   繁体   中英

How to drag the QLabel from one window to another in Qt?

I am learning Qt for fun. And I got a question:

How could I drag and drop the QLabel in Qt among two different windows?

Here is what I have so far:

在此处输入图片说明

As you can tell from the .gif (which does not want to become downloaded and visible here for some reasons, but if you click on the link to it, you can clearly see it) provided above right now there are two main problems:

  1. I can not move the QLabel outside of the window (and hence am not able to register the drag and drop event).

  2. The label is flashing for some reasons when I am moving it.

Here is the relevant part of the implementation from the .gif :

#ifndef DRAGGERP_H
#define DRAGGERP_H

#include <QLabel>
#include <QApplication>
#include <QMouseEvent>
#include <QPoint>

class DraggerP : public QLabel
{
    QPoint offset;
    QPoint startingPosition;


public:
    DraggerP(QWidget* parent = nullptr) : QLabel(parent){ }

protected:
    void enterEvent(QEvent* event) override
    {
        QApplication::setOverrideCursor(Qt::PointingHandCursor);
    }

    void leaveEvent(QEvent* event) override
    {
        QApplication::restoreOverrideCursor();
    }

    void mousePressEvent(QMouseEvent* event) override
    {
        startingPosition = pos();
        offset = QPoint(
            event->pos().x() - pos().x() + 0.5*width(),
            event->pos().y() - pos().y() + 0.5*height()
        );
    }

    void mouseMoveEvent(QMouseEvent* event) override
    {
        move(event->pos() + offset);
    }

    void mouseReleaseEvent(QMouseEvent* event) override
    {
        move(startingPosition);
    }
};

#endif // DRAGGERP_H

This is the extension of the QLabel I am using to create the drag and drop effect.

I do not need the whole solution, at least an idea of how to accomplish this and what am I doing wrong here.

Here is a pretty good example and I used it as a starting point.

That strange movement that the QLabel suffers is because the position of the QLabel now depends on the layout, the job of the layout is to establish the position of the widgets depending on the policies you establish.

The solution is not to implement those actions in the QLabel but in the MainWindow as I show below:

#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QTime>
#include <QDrag>
#include <QMimeData>
#include <QMouseEvent>

class MainWindow: public QMainWindow {
    QScrollArea scrollArea;
    QWidget contentWidget;
    QVBoxLayout lay;
public:
    MainWindow(QWidget* parent=nullptr): QMainWindow(parent){
        qsrand((uint) QTime::currentTime().msec());
        setCentralWidget(&scrollArea);
        scrollArea.setWidget(&contentWidget);
        contentWidget.setLayout(&lay);
        scrollArea.setWidgetResizable(true);
        for(int i=0; i< 20; i++){
            QLabel *label = new QLabel(QString("label %1").arg(i));
            QPalette pal = label->palette();
            pal.setColor(QPalette::Background, QColor(10 +qrand() % 240, 10 +qrand() % 240, 10 +qrand() % 240));
            label->setAutoFillBackground(true);
            label->setPalette(pal);
            lay.addWidget(label);
        }
        setAcceptDrops(true);
    }
protected:
    void mousePressEvent(QMouseEvent *event){
        QMainWindow::mousePressEvent(event);
        QWidget *child = childAt(event->pos());
        if(qobject_cast<QLabel *>(child))
            createDrag(event->pos(), child);
    }

    void dropEvent(QDropEvent *event){
        QByteArray byteArray = event->mimeData()->data("Label");
        QWidget * widget = *reinterpret_cast<QWidget**>(byteArray.data());
        QLabel * new_label =  qobject_cast<QLabel *>(widget);

        QWidget *current_children = childAt(event->pos());
        QLabel * current_label = qobject_cast<QLabel*>(current_children);
        int index = 0;
        if(new_label){
            if(current_label)
                index = lay.indexOf(current_label);
            else{
                index = 0;
                QLayoutItem *item = lay.itemAt(index);
                while(item->widget()->pos().y() < event->pos().y() && item) 
                    item = lay.itemAt(index++);
            }
            lay.insertWidget(index, new_label);
        }
    }

private:
    void createDrag(const QPoint &pos, QWidget *widget){
        if(widget == Q_NULLPTR)
            return;
        QByteArray byteArray(reinterpret_cast<char*>(&widget),sizeof(QWidget*));
        QDrag *drag = new QDrag(this);
        QMimeData * mimeData = new QMimeData;
        mimeData->setData("Label",byteArray);
        drag->setMimeData(mimeData);
        QPoint globalPos = mapToGlobal(pos);
        QPoint p = widget->mapFromGlobal(globalPos);
        drag->setHotSpot(p);
        drag->setPixmap(widget->grab());
        drag->exec(Qt::CopyAction | Qt::MoveAction);
    }
protected:
    void dragEnterEvent(QDragEnterEvent *event){
       if(event->mimeData()->hasFormat("Label"))
        event->acceptProposedAction();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w1;
    MainWindow w2;
    w1.show();
    w2.show();
    return a.exec();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM