Gabriel_Br
Gabriel_Br

Reputation: 119

Qt - How to show image/icon/data while dragging an item?

I have an application where I can drag an item to a QGraphicsScene and create a new object depending on the item text, but how can I change the data being displayed while moving around the item?

for example, instead of a text, I want to show an icon:

enter image description here

I have a list with some itens:

OptionList::OptionList(QWidget *parent) : QListWidget(parent)
{
    this->setDragEnabled(true);
    this->setDropIndicatorShown(true);
    this->setSelectionMode(QAbstractItemView::SingleSelection);
    this->setDefaultDropAction(Qt::CopyAction);
    this->setViewMode(QListView::ListMode);

    for(const QString &color : {"Blue", "Red", "Green", "Yellow"})
    {
        OptionItem *item = new OptionItem;
        item->setText(color);
        item->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
        addItem(item);
    }
}

I drop the itens into the scene to create a new object:

MyScene::MyScene()
{
    setBackgroundBrush(Qt::lightGray);
}

void MyScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);
}

void MyScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);
}

void MyScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    QByteArray encoded = event->mimeData()->data("application/x-qabstractitemmodeldatalist");
    QDataStream stream(&encoded, QIODevice::ReadOnly);

    QStringList colors;

    while (!stream.atEnd())
    {
        int row, col;
        QMap<int,  QVariant> roleDataMap;
        stream >> row >> col >> roleDataMap;
        colors << roleDataMap[Qt::DisplayRole].toString();
    }

    QPointF posView = event->scenePos() ;

    for(const QString & color: colors)
    {
        Block *newBlock = new Block(color);
        newBlock->setPos(posView);
        addItem(newBlock);
    }
}

Then, I created OptionItem class, derived from QListWidgetItem, and reimplemented the mousePressEvent, mouseMoveEvent and mouseReleaseEvent

OptionItem::OptionItem()
{

}

void OptionItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->setAccepted(true);
}

void OptionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QDrag *drag = new QDrag(event->widget());

    QMimeData *mime = new QMimeData;

    QImage image(":/images/MyIcon_icon.png");
    mime->setImageData(image);

    drag->setMimeData(mime);
    drag->setPixmap(QPixmap::fromImage(image));
    drag->setHotSpot(QPoint(15, 30));

    drag->exec();

    event->setAccepted(true);
}

void OptionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    event->setAccepted(true);
}

I tried to follow the drag drop robot example in the Qt Creator but it isn't the same thing

It seems that the image appears very quickly when I start dragging an item

Is there a way to show the icon while dragging the item through the whole operation?

Upvotes: 1

Views: 2593

Answers (2)

oscarz
oscarz

Reputation: 1254

The above is correct!

Also should note that drag->setMimeData(data); needs to be called after drag->setPixmap(pixmap);.

Otherwise, during the drag moving, it will show the original mimedata type instead of showing an image/icon.

Upvotes: 0

eyllanesc
eyllanesc

Reputation: 243907

The classes that inherit from QAbstractItemView support the default drag so they already have implemented methods, instead the example you point out shows how to implement this functionality for some class that does not have it, the task in your case is simple, you must overwrite the method startDrag of QListWidget.

optionilist.h

#ifndef OPTIONLIST_H
#define OPTIONLIST_H

#include <QListWidget>


class OptionList: public QListWidget{
public:
    OptionList(QWidget* parent=nullptr);

protected:
    void startDrag(Qt::DropActions supportedActions);
};

#endif // OPTIONLIST_H

optionlist.cpp

#include "optionlist.h"

#include <QDrag>

OptionList::OptionList(QWidget *parent): QListWidget(parent){

    setDragEnabled(true);
    setDropIndicatorShown(true);
    setSelectionMode(QAbstractItemView::SingleSelection);
    setDefaultDropAction(Qt::CopyAction);
    setViewMode(QListView::ListMode);

    for(const QString &color : {"Blue", "Red", "Green", "Yellow"}){
        QListWidgetItem *blue = new QListWidgetItem;
        blue->setText(color);
        blue->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
        addItem(blue);
    }
}

void OptionList::startDrag(Qt::DropActions supportedActions){
    if(supportedActions & Qt::CopyAction){
        QList<QListWidgetItem *> m_items = selectedItems();
        if(m_items.isEmpty())
            return;
        QMimeData *data = mimeData(m_items);
        QDrag *drag = new QDrag(this);
        QPixmap pixmap(":/images/MyIcon_icon.png");
        drag->setPixmap(pixmap);
        drag->setMimeData(data);
        drag->setHotSpot(pixmap.rect().center());
        drag->exec(Qt::CopyAction);
    }
    else
        QListWidget::startDrag(supportedActions);

}

The complete code can be found at the following link.

Upvotes: 2

Related Questions