Qt Drag&DropDrag and place

This article is part of the Qt Lab-CSDN blog series

The drag-and-drop operation includes two actions: drag and drop.

Drag allowed

For the window or control to be dragged out, setDragEnabled(true)

For the window or control to be dragged in, setAcceptDrops(true)

The following is a specific use case to illustrate

Drag items in the list control

This use case implements dragging from the list window on the left and dragging into the Widget window on the right.

Main interface settings

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->resize(1200,800);
    //Drag from ProjectListWidget to MyWidget
    QSplitter* center=new QSplitter;
    center->addWidget(new ProjectListWidget);
    center->addWidget(new MyWidget);

    center->setOrientation(Qt::Horizontal);
    this->setCentralWidget(center);
}

Left list window settings

class ProjectListWidget : public QListWidget
{
    Q_OBJECT
public:
    ProjectListWidget();

    // QAbstractItemView interface
protected:
    void startDrag(Qt::DropActions supportedActions);
};

The left window allows dragging its item, and the text in the item is stored in QMimeData for transfer to the right form.

ProjectListWidget::ProjectListWidget()
{
    this->addItem("item1");
    this->addItem("item2");
    //(1) Enable dragging. If it is not enabled, there will be no effect of dragging the item.
    this->setDragEnabled(true);
}

//(2) Start dragging and set a drag data marked x1
void ProjectListWidget::startDrag(Qt::DropActions supportedActions)
{
    QString text=this->currentItem()->text();
    QMimeData* mimeData=new QMimeData;
    mimeData->setData("x1",text.toLocal8Bit());
    QDrag* drag=new QDrag(this);
    drag->setMimeData(mimeData);
    drag->exec();
}

The form on the right has more implementations. First, the drag entry event dragEnterEvent must be allowed, and then the drag move event dragMoveEvent must be allowed. Finally, implement dropEvent to receive data.

MyWidget::MyWidget(QWidget *parent)
    : QWidget{parent}
{
    //(1) Enable placement. If not enabled, a prohibition symbol will be displayed when dragging into the interface.
    this->setAcceptDrops(true);
}

//(2) After implementing the following two methods, the interface can allow drag and drop entry.
//Allow drag-and-drop entry for a type of drag data marked x1
void MyWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("x1"))
        event->accept();
    else
        event->ignore();
}

void MyWidget::dragMoveEvent(QDragMoveEvent *event)
{
    if (event->mimeData()->hasFormat("x1"))
        event->accept();
    else
        event->ignore();
}

//(3) Implement dropEvent to receive the data carried by dragging
void MyWidget::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasFormat("x1"))
    {
        QString text(event->mimeData()->data("x1"));
        QPoint pos=event->pos();
        //Put the dragged data into the list here, and then draw it through paintEvent()
        m_textList.append({text,pos});
        event->accept();
        this->update();
    }
    else
        event->ignore();
}

void MyWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    for(int i=0;i<m_textList.size();i + + )
    {
        QPoint pos=m_textList.at(i).second;
        QString text=m_textList.at(i).first;
        painter.drawText(pos,text);
    }
}

The final effect is as follows

Event emission sequence and delivery rules

The above picture is referenced from Qt Drag and Drop (1): Basic Principles of Drag and Drop (QDrag Class) – CSDN Blog

About QDrag.exec()

void ProjectListWidget::startDrag(Qt::DropActions supportedActions)
{
    //When calling this method, click on the item and move the mouse to enter the method
    //Then execute until drag->exec() blocks
    //The exec() function is a blocking function (but it will not block the main event loop)
    //In other words, "after drag" will not be printed before releasing the mouse.
    //But the window can still get other event responses. For example, mainwindow can still respond to update() triggered by QTimer.
    QString text=this->currentItem()->text();
    QMimeData* mimeData=new QMimeData;
    mimeData->setData("x1",text.toLocal8Bit());
    QDrag* drag=new QDrag(this);
    drag->setMimeData(mimeData);
    qDebug()<<"before drag";
    drag->exec();
    qDebug()<<"after drag";
}

Add the following code when constructing MainWindow:

 QTimer* timer=new QTimer(this);
    timer->setInterval(1000);
    connect(timer, & amp;QTimer::timeout,[=]{
        qDebug()<<"update...";
        this->update();
    });
    timer->start();

Test whether the main window can respond to other events when the mouse is not released during dragging (yes)

bool MainWindow::event(QEvent *event)
{
    qDebug()<<"event::"<<event;
    return QMainWindow::event(event);
}

Drag the content in the Widget to another window or control

In the above example, the time to start dragging is within the startDrag() method. QListWidget::startDrag() can be rewritten, but for ordinary QWidgets, this method is not available

This example uses a LeftWidget inherited from QWidget as an example. Usually enable dragging in mousePressEvent()

void LeftWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        QString text="xxxxxxx";
        QMimeData* mimeData=new QMimeData;
        mimeData->setData("x1",text.toLocal8Bit());
        QDrag* drag=new QDrag(this);
        drag->setMimeData(mimeData);
        qDebug()<<"before drag";
        drag->exec();
        qDebug()<<"after drag";
    }
}

Continue to use MainWindow and MyWidget from the previous example to achieve the effect of dragging from LeftWidget to MyWidget

If you want to drag a button to another interface and move its text to another window

You can do this by inheriting QPushButton and then overriding its mousePressEvent, almost the same as overriding LeftWidget::mousePressEvent.

void MyButton::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        QString text=this->text();
        QMimeData* mimeData=new QMimeData;
        mimeData->setData("x1",text.toLocal8Bit());
        QDrag* drag=new QDrag(this);
        drag->setMimeData(mimeData);
        qDebug()<<"before drag";
        drag->exec();
        qDebug()<<"after drag";
    }
    return QPushButton::mousePressEvent(event);
}

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. MySQL entry-level skills treeDatabase compositionTable 78128 people are learning the system