1

I've the following situation:

Example

Basically I've a QTreeWidget with some items, and a canvas that's a subclass of a QGraphicsView. What I want to accomplish is to drag a QTreeWidgetItem in the QGraphicsView subclass. When the mouse is released in the QGraphicsView subclass I want to create a new shape (let's say a circle) with some data of the dragged item (let's say the name itself written inside the circle).

I was able to enable the drag from the QTreeWidget by using the setDragEnabled(true) method, and I'm able to receive the event in the QGraphicsView, because when I enter its area it calls the dragEnterEvent.

In my subclass I've a QGraphicsScene, like this:

#ifndef SEQUENCECANVAS_HPP_
#define SEQUENCECANVAS_HPP_

#include <QWidget>
#include <QGraphicsScene>
#include <QGraphicsView>

class SequenceCanvas : public QGraphicsView {

  Q_OBJECT

public:

  SequenceCanvas(QWidget* parent = nullptr);
  virtual ~SequenceCanvas() = default;

protected:

  void dragEnterEvent(QDragEnterEvent* event) override;
  void dropEvent(QDropEvent* event) override;

private:

  void createWidgets();
  void createLayout();

private:

  QGraphicsScene m_scene;
};

#endif // !SEQUENCECANVAS_HPP_
#include "SequenceCanvas.hpp"
#include <QString>
#include <QHBoxLayout>
#include <QDragEnterEvent>
#include <QMimeData>

SequenceCanvas::SequenceCanvas(QWidget* parent) :
  QGraphicsView(parent) {
  createWidgets();
  createLayout();
  setScene(&m_scene);
  setAcceptDrops(true);
}

void SequenceCanvas::dragEnterEvent(QDragEnterEvent* event) {
  event->acceptProposedAction(); // no filter at the moment I just want to test
}

void SequenceCanvas::dropEvent(QDropEvent* event) {
  int i = 0; // just for putting a breakpoint now. Its breakpoint is never raised
}

void SequenceCanvas::createWidgets() {

}

void SequenceCanvas::createLayout() {

}

Even if the dragEnterEvent is called when my mouse enter my widget during the drag, the dropEvent method is not called, so when I release the mouse inside my SequenceCanvas class nothing happens.

Basically I've two questions:

  • How can I raise the drop event inside my SequenceCanvas class that's a subclass of QGraphicsView?
  • How can I pass custom data (let's say a vector of strings) with the drop event, so I can pass all needed information for managing the event?

EDIT:

I missed to reimplement the void dragMoveEvent(QDragMoveEvent* event) method. I've added it and now I receive drop events. I need to know how to pass custom data with a drag-drop event now... Thanks to zeFrenchy.

My class body now is:

SequenceCanvas::SequenceCanvas(QWidget* parent) :
  QGraphicsView(parent) {
  createWidgets();
  createLayout();
  setScene(&m_scene);
  setAcceptDrops(true);
  bool ok = acceptDrops();
}

///////////////////////////////////////////////////////////////////////////////
// VIRTUAL PROTECTED SECTION                                                 //
///////////////////////////////////////////////////////////////////////////////

void SequenceCanvas::dragEnterEvent(QDragEnterEvent* event) {
  event->acceptProposedAction();
}

void SequenceCanvas::dragMoveEvent(QDragMoveEvent* event) {
  event->acceptProposedAction();
}

void SequenceCanvas::dropEvent(QDropEvent* event) {
  int i = 0;
}

///////////////////////////////////////////////////////////////////////////////
// PRIVATE SECTION                                                           //
///////////////////////////////////////////////////////////////////////////////

void SequenceCanvas::createWidgets() {

}

void SequenceCanvas::createLayout() {

}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Jepessen
  • 11,744
  • 14
  • 82
  • 149
  • is acceptDrops set to true on your widget? – zeFrenchy Jun 08 '20 at 09:38
  • I call `setAcceptDrops(true);` in the `SequenceDiagram` constructor. If I call `acceptDrops()` after it it returns `true`. – Jepessen Jun 08 '20 at 09:40
  • oops, missed that – zeFrenchy Jun 08 '20 at 09:42
  • 1
    The doc says this about the DragMoveEvent (worth a try just accepting the action): A widget will receive drag move events repeatedly while the drag is within its boundaries, if it accepts drop events and enter events. The widget should examine the event to see what kind of data it provides, and call the accept() function to accept the drop if appropriate. – zeFrenchy Jun 08 '20 at 09:49
  • 1
    I suspect the drag/drop events need to be handled by the viewport rather than the `QGraphicsView` itself. Try either installing an event filter on the viewport widget or setting your own custom viewport widget that handles the relevant event. – G.M. Jun 08 '20 at 09:50
  • Ok thanks. I've implemented the `dragMoveEvent` and now I receive the drop event. Now how can I pass custom data? – Jepessen Jun 08 '20 at 09:54
  • Glad I could help a bit, but I believe, there a one question at a time policy in place! – zeFrenchy Jun 08 '20 at 10:08
  • I've turned my comment into an answer in the event you decide to keep your question as originaly asked. – zeFrenchy Jun 08 '20 at 10:13
  • @Jepessen, I am having the same exact issue. Did you find a solution to this question? If so could you please share it? I noticed that on the EDITS you asked also another question and did you find an answer to that question too Thanks :) – Emanuele Oct 09 '20 at 15:17

1 Answers1

1

The documentation says the following about DragMoveEvent:

A widget will receive drag move events repeatedly while the drag is within its boundaries, if it accepts drop events and enter events. The widget should examine the event to see what kind of data it provides, and call the accept() function to accept the drop if appropriate.

So you should be provide an override for dragMoveEvent(QDragMoveEvent* event) in which you simply accept the proposed action.

zeFrenchy
  • 6,541
  • 1
  • 27
  • 36