Drag and drop issue - dragged element teleports to 0,0 when begginning to drag, then follows normally
Unsolved
General and Desktop
-
Hello there, title says it all. I am an absolute beginner in Qt and I am struggling to resolve a bug I have stumbled upon. I have a list of nodes and they should exchange positions when dragged over one another. They do that except, when beginning to drag, the node snaps to position 0,0 and then in that offset drags along with the mouse. I only have one function which takes care of positioning them (RefreshNodePositions()) - I have checked and it does not execute when this bug happens, so I do not know what could cause it.
I am lost on how to find the root of issue. Any advice much appreciated!
This is the "canvas" which holds the nodes#include "sequenceeditorwidget.h" #include "ui_sequenceeditorwidget.h" #include "sequencediagramnodeview.h" #include <QKeyEvent> #include <QKeySequence> #include <QMessageBox> SequenceEditorWidget::SequenceEditorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::SequenceEditorWidget) { ui->setupUi(this); QObject::connect( ui->addObject_button, &QPushButton::clicked, this, &SequenceEditorWidget::onAddObject); scene = new QGraphicsScene(ui->sequenceGraphicsView); ui->sequenceGraphicsView->setScene(scene); ui->sequenceGraphicsView->setDragMode(QGraphicsView::RubberBandDrag); ui->sequenceGraphicsView->setRenderHints(QPainter::Antialiasing |QPainter::TextAntialiasing); ui->sequenceGraphicsView->setAlignment(Qt::AlignTop | Qt::AlignLeft); } SequenceEditorWidget::~SequenceEditorWidget() { delete ui; } void SequenceEditorWidget::ChangeNodeName(const QString &name, int nodeID) { for(int i = 0; i < diagramNodes.length(); i++) { if(diagramNodes[i]->nodeId == nodeID) { diagramNodes[i]->model->setName(name); RefreshNodePositions(); break; } } } int SequenceEditorWidget::getIndexOfNodeAtPos(QPointF pos) { if(diagramNodes.length() <= 1 || pos.x() <= 0) { return 0; } for(int i = 0; i < diagramNodes.length() - 1; i++) { if(pos.x() > diagramNodes[diagramNodes.length() - 1]->getSlotPosition().x()) { return diagramNodes.length() - 1; } else if(pos.x() < 0) { return 0; } if(pos.x() >= diagramNodes[i]->getSlotPosition().x() && pos.x() < diagramNodes[i+1]->getSlotPosition().x()) { return i; } } return -1; } int SequenceEditorWidget::getIndexOfNodeByID(int nodeID) { for(int i = 0; i < diagramNodes.length(); i++) { if(diagramNodes[i]->nodeId == nodeID) { return i; } } return -1; } void SequenceEditorWidget::putNodeAtPos(QPointF pos, int nodeID) { int firstNodeIndex = getIndexOfNodeByID(nodeID); int secondNodeIndex = getIndexOfNodeAtPos(pos); QMessageBox::information(this, QString::number(firstNodeIndex), QString::number(secondNodeIndex)); diagramNodes.swapItemsAt(firstNodeIndex, secondNodeIndex); RefreshNodePositions(); } void SequenceEditorWidget::RefreshNodePositions() { QMessageBox::information(nullptr, "EXECUTED", "EXECUTED"); *posToPlaceNextNode = *posAnchorNode; for(int i = 0; i < diagramNodes.length(); i++) { diagramNodes[i]->setSlotPosition(posToPlaceNextNode); posToPlaceNextNode->setX(posToPlaceNextNode->x() + diagramNodes[i]->boundingRect().width() + 30); } } void SequenceEditorWidget::onAddObject() { SequenceDiagramNodeView* newNode = new SequenceDiagramNodeView(this, nodeIdCounter++, posToPlaceNextNode); diagramNodes.append(newNode); posToPlaceNextNode->setX(posToPlaceNextNode->x() + newNode->boundingRect().width() + 30); scene->addItem(newNode); } void SequenceEditorWidget::keyPressEvent(QKeyEvent* event) { if(event->key() == Qt::Key_Delete) { QList<QGraphicsItem *> selected = scene->selectedItems(); QMutableListIterator<QGraphicsItem *> i(selected); for(int i = 0; i < scene->selectedItems().length(); i++) { QString typeOfObject = typeid(scene->selectedItems()[i]).name(); { if(typeOfObject.compare("SequenceDiagramNodeView*")) { SequenceDiagramNodeView* nodeToRemove = (SequenceDiagramNodeView*)scene->selectedItems()[i]; for (int j = 0; j < diagramNodes.length(); j++) { if(nodeToRemove->nodeId == diagramNodes[j]->nodeId) { diagramNodes.removeAt(j); } } } } } qDeleteAll(selected); RefreshNodePositions(); } }
And this is the view of the node itself
#include <QStyleOptionGraphicsItem> #include <QPen> #include <QPainter> #include "sequencediagramnodeview.h" #include "sequencediagramnodemodel.h" #include <QStyleOptionGraphicsItem> #include <QPen> #include <QPainter> SequenceDiagramNodeView::SequenceDiagramNodeView(QWidget *parent, int nodeID, QPointF* slotPos) { this->model = new SequenceDiagramNodeModel(); this->nodeId = nodeID; model->setName(QString::number(nodeID)); this->controller = new sequenceDiagramNodeController(parent); this->parent = parent; this->textColor = Qt::darkGreen; this->backgroundColor = Qt::white; this->outlineColor = Qt::darkBlue; this->slotPosition = *slotPos; this->setPos(this->slotPosition); setFlags(ItemIsMovable | ItemIsSelectable); setFlag(ItemSendsGeometryChanges); } QPointF SequenceDiagramNodeView::getSlotPosition() { return this->slotPosition; } void SequenceDiagramNodeView::setSlotPosition(QPointF* pos) { this->slotPosition = *pos; this->setPos(this->slotPosition); } SequenceDiagramNodeView::~SequenceDiagramNodeView() { } QRectF SequenceDiagramNodeView::boundingRect() const { const int Margin = 1; return getOutlineRect().adjusted(-Margin, -Margin, +Margin, +Margin); } void SequenceDiagramNodeView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { QPen pen(outlineColor); if (option->state & QStyle::State_Selected) { pen.setStyle(Qt::DotLine); pen.setWidth(2); } painter->setPen(pen); painter->setBrush(backgroundColor); QFontMetricsF metrics{qApp->font()}; // Draw outline rect QRectF outlineRect = getOutlineRect(); painter->drawRect(outlineRect); pen.setStyle(Qt::SolidLine); // Draw name QFont font = painter->font(); font.setBold(true); painter->setFont(font); painter->setPen(textColor); painter->drawText(getTextRect(model->getName(), 0, 0), Qt::AlignLeft, model->getName()); font.setBold(false); painter->setFont(font); } QRectF SequenceDiagramNodeView::getOutlineRect() const { const int PADDING = 8; QFontMetricsF metrics{qApp->font()}; qreal width = metrics.boundingRect(model->getName()).width(); qreal height = (metrics.height()) * 2; QRectF rect{0, -PADDING * 1.5, width, height}; // TODO: Why? rect.adjust(-PADDING, -PADDING, +PADDING, +PADDING); return rect; } void SequenceDiagramNodeView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { controller->createEditNameDialog(this->nodeId); } void SequenceDiagramNodeView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { // Get center of the node QPointF pos = this->scenePos() + this->boundingRect().center(); controller->droppedNodeAtPos(pos, this->nodeId); } QRectF SequenceDiagramNodeView::getTextRect(QString text, qreal dx, qreal dy) const { const int PADDING = 2; QFontMetricsF metrics{qApp->font()}; QRectF rect = metrics.boundingRect(text); rect.adjust(-PADDING, -PADDING, +2*PADDING, +PADDING); rect.translate(dx, dy); return rect; }