QGraphicsWidget and drag&drop



  • Hello! I created a very simple test application to test the drag & drop mechanism in a graphics scene.

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    //setup scene and view
    QGraphicsView *view = new QGraphicsView(ui->centralWidget);
    QGraphicsScene *scene = new QGraphicsScene(0, 0, 2000, 2000, view);
    scene->setSceneRect(-100,-100,400,400);
    view->setTransformationAnchor(QGraphicsView::NoAnchor);
    view->setScene(scene);
    
    //create textedit, should be able to accept drag & drop
    QTextEdit *edit = new QTextEdit(0);
    edit->setAcceptDrops(true);
    QGraphicsProxyWidget *proxy = scene->addWidget(edit);
    proxy->setGeometry( QRectF( 0,0,100,60));
    proxy->setAcceptDrops(true);
    
    //just create an additional button as another widget which should be able to accept drag & drop, too
    QPushButton *btn = new QPushButton(0);
    btn->setAcceptDrops(true);
    QGraphicsProxyWidget *proxy2 = scene->addWidget(btn);
    proxy2->setGeometry( QRectF( 0,110,60,25));
    proxy2->setAcceptDrops(true);
    
    //this circle can be draged to another item
    MyEllipse *ell = new MyEllipse();
    ell->setRect(QRectF(120,30,20,20) );
    scene->addItem(ell);
    ell->installSceneEventFilter(ell);
    
    //another circle which can receive drops as intended
    QGraphicsEllipseItem *ell2 = new QGraphicsEllipseItem();
    ell2->setRect(QRectF(120,70,20,20) );
    ell2->setAcceptDrops(true);
    scene->addItem(ell2);
    

    }@

    We have a QTextEdit and a QPushButton on the scene. An ellipse (MyEllipse *ell) which will act a source for the drag&drop and a second ellipse (ell2) as an additional drop destination. Source for MyEllipse:

    @MyEllipse::MyEllipse()
    {

    }

    bool MyEllipse::sceneEventFilter(QGraphicsItem watched, QEvent event)
    {
    if( event->type() == QEvent::GraphicsSceneMousePress)
    {
    QGraphicsSceneMouseEvent e = dynamic_cast<QGraphicsSceneMouseEvent>(event);
    qDebug() << " yes, drag";
    QMimeData
    mime = new QMimeData();
    QDrag
    drag = new QDrag((QObject*)e->widget());
    drag->setMimeData(mime);
    drag->exec();
    }
    }@

    The problem: ell2 will accept the drop event as intended - the mouse cursor changes, the handling of the drop event is missing in my example. But in case of edit and btn the cursor does not change, therefore, the drop event will be ignored. But why, or better: how to fix this problem?



  • OK, I recently found the solution ("QtFAQ":http://qt-project.org/faq/answer/how_can_i_do_drag_and_drop_in_a_widget), you definitely have to override dragEnterEvent and dragMoveEvent and "manually" accept the event. I do not know why this is necessary even though setAcceptDrops is set true. Is this a design mistake in the Qt framework or is there any good reason why it is realized this way?

    Here is the solution to make the Button able to receive and handle a drop event:

    @class MyButton : public QPushButton
    {
    public:
    MyButton();

    virtual void dragEnterEvent(QDragEnterEvent *event)
    {
        event->acceptProposedAction();
    }
    
    virtual void dragMoveEvent(QDragMoveEvent *de)
    {
        de->accept();
    }
    
    virtual void dropEvent(QDropEvent *de)
    {
        qDebug() << "dropped ...";
        qDebug("Contents: %s", de->mimeData()->text().toLatin1().data());
    }
    

    };@


  • Lifetime Qt Champion

    Hi and welcome to devnt,

    setAcceptDrops means that you would like your item to be able to react to drag and drop events. However, it's up to you tell when it it's actually time to accept something. e.g. you could have a text rendering item that should only accept drops when the content of the mime data has text in it and not the rest of the time. Or if you take a word processing application it won't accept e.g. PDF but will for plain text file.

    Hope it helps


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.