1
votes

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() {

}
1
is acceptDrops set to true on your widget?zeFrenchy
I call setAcceptDrops(true); in the SequenceDiagram constructor. If I call acceptDrops() after it it returns true.Jepessen
oops, missed that 😅zeFrenchy
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
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.

1 Answers

1
votes

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.