Как перетащить QLabel из одного окна в другое в Qt? - PullRequest
0 голосов
/ 26 мая 2018

Я учу Qt для удовольствия.И у меня возник вопрос:

Как я могу перетащить QLabel в Qt между двумя разными окнами?

Вот что у меня так далеко:

enter image description here

Как вы можете сказать из .gif (который не хочет быть загруженным и видимым здесь по некоторым причинам, но если вы нажмете на ссылку на него, вы можете ясно увидетьit) при условии, что выше прямо сейчас есть две основные проблемы:

  1. Я не могу переместить QLabel за пределы окна (и, следовательно, не могу зарегистрировать событие перетаскивания).

  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, которое я использую для создания эффекта перетаскивания.

Мне не нужно полное решение, по крайней мере, идеякак это сделать и что я здесь делаю не так.

Здесь - довольно хороший примери я использовал это как отправную точку.

1 Ответ

0 голосов
/ 27 мая 2018

Странное движение, от которого страдает QLabel, заключается в том, что положение QLabel теперь зависит от макета, а работа макета заключается в определении положения виджетов в зависимости от установленных вами политик.

Решение состоит не в том, чтобы реализовать эти действия в QLabel, а в главном окне, как показано ниже:

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