如何在 Qt 中将 QLabel 从一个 window 拖到另一个?

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

我学习 Qt 是为了好玩。我有一个问题:

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

这是我目前的情况:

.gif 中可以看出(由于某些原因不想在此处下载和显示,但是如果单击 link 可以清楚地看到它) 上面提供的现在有两个主要问题:

  1. 我无法将 QLabel 移动到 window 之外(因此无法注册拖放事件)。

  2. 标签在移动的时候因为某些原因闪烁

这里是 .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

这是我用来创建拖放效果的 QLabel 的扩展。

我不需要整个解决方案,至少需要知道如何实现这个以及我在这里做错了什么。

Here 是一个很好的例子,我用它作为起点。

QLabel 出现的奇怪移动是因为 QLabel 的位置现在取决于布局,布局的工作是根据策略建立小部件的位置你建立。

解决方案不是在 QLabel 中实现这些操作,而是在 MainWindow 中实现,如下所示:

#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();
}