Qt - drag and drop with graphics view framework

Posted by David Davidson on Stack Overflow See other posts from Stack Overflow or by David Davidson
Published on 2010-04-28T18:59:41Z Indexed on 2010/04/30 18:17 UTC
Read the original article Hit count: 487

Filed under:
|
|

I'm trying to make a simple draggable item using the graphics framework. Here's the code for what I did so far:

Widget class:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    DragScene *scene = new DragScene();
    DragView *view = new DragView();
    QHBoxLayout *layout = new QHBoxLayout();

    DragItem *item = new DragItem();
    view->setAcceptDrops(true);
    scene->addItem(item);
    view->setScene(scene);
    layout->addWidget(view);
    this->setLayout(layout);

}

Widget::~Widget()
{
}

DragView class:

class DragView : public QGraphicsView
{
public:
    DragView(QWidget *parent = 0);
};

DragView::DragView(QWidget *parent) : QGraphicsView(parent)
{
    setRenderHints(QPainter::Antialiasing);
}

DragScene class:

class DragScene : public QGraphicsScene
{
public:
    DragScene(QObject* parent = 0);

protected:
    void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
    void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
    void dropEvent(QGraphicsSceneDragDropEvent *event);
};

DragScene::DragScene(QObject* parent) : QGraphicsScene(parent)
{
}

void DragScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dropEvent(QGraphicsSceneDragDropEvent *event){
    qDebug() << event->pos();
    event->acceptProposedAction();
    DragItem *item = new DragItem();
    this->addItem(item);
    item->setPos(event->pos());
}

DragItem class:

class DragItem : public QGraphicsItem
{
public:
    DragItem(QGraphicsItem *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);

protected:
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

DragItem::DragItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    setFlag(QGraphicsItem::ItemIsMovable);
}

QRectF DragItem::boundingRect() const{
    const QPointF *p0 = new QPointF(-10,-10);
    const QPointF *p1 = new QPointF(10,10);
    return QRectF(*p0,*p1);
}

void DragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    if(painter == 0)
        painter = new QPainter();
    painter->drawEllipse(QPoint(0,0),10,10);
}

void DragItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){

}

void DragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
}

void DragItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
    QMimeData* mime = new QMimeData();
    QDrag* drag = new QDrag(event->widget());
    drag->setMimeData(mime);
    drag->exec();
}

void DragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
}

main.cpp instantiates a Widget and shows it. When I try to drag the circle, the app just creates another circle over the original one, regardless of where I release the drag. qDebug() in DragScene's dropEvent() shows QPointF(0,0) everytime the drag ends. I'm having a hard time trying to understand exactly what I have to do, which classes I should subclass, which methods needs to be overriden, to make this work. The documentation on this isn't very detailed. I'd like to know how to make this work, and if there's some other, more comprehensive resource to learn about the graphics view framework, besides the official documentation (which is excellent btw, but it would be great if there was a more detailed treatise on the subject).

EDIT:

Following badgerr's advice, I replaced item->pos() in DragScene::dropEvent() with item->scenePos(), now the drop event creates a new circle in the drop site, which is more or less what I wanted. But the original circle is still in place, and while the drag is in progress, the item doesn't follow the mouse cursor.

The QGraphicsSceneDragDropEvent documentation says that pos() should return the cursor position in relation to the view that sent the event, which, unless I got it wrong, shouldn't be (0,0) all the time. Weird.

I've read in a forum post that you can use QDrag::setPixMap() to show something during the drag, and in examples I've seen pictures being set as pixmaps, but how do I make the pixmap just like the graphics item I'm supposed to be dragging?

© Stack Overflow or respective owner

Related posts about qt

Related posts about qgraphicsview