t0bias
t0bias

Reputation: 133

Strange effect on QGraphicsView upon Reimplementation of Mouse Event

I started a small Project using this source-code:

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGraphicsLineItem>

class CustomRectItem : public QGraphicsRectItem
{
public:
    CustomRectItem (const QRectF& rect) : QGraphicsRectItem(rect) {
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
    setAcceptHoverEvents(true);
}

void addLine(QGraphicsLineItem *line1, QGraphicsLineItem *line2) {
    if (this->data(0).toString() == "_p1") {
        this->leftLine = line1;
        this->topLine = line2;
    }
    if (this->data(0).toString() == "_p2") {
        this->topLine = line1;
        this->rightLine = line2;
    }
    if (this->data(0).toString() == "_p3") {
        this->rightLine = line1;
        this->bottomLine = line2;
    }
    if (this->data(0).toString() == "_p4") {
        this->bottomLine = line1;
        this->leftLine = line2;
    }
}

QPointF center(void) {
    return QPointF((rect().x() + rect().width() / 2),
                   (rect().y() + rect().height() / 2));
}

QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionChange && scene()) {
        // value is the new position.
        QPointF newPos = value.toPointF();

        moveLineToCenter(newPos, this->data(0).toString());
    }
    return QGraphicsItem::itemChange(change, value);
}

void moveLineToCenter(QPointF newPos, QString pointString) {
    // Converts the polygon upper left position
    // to the upper left "handle"-rect center position
    qreal xOffset = rect().x() + rect().width()/2;
    qreal yOffset = rect().y() + rect().height()/2;

    QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);

    QPointF p1;
    QPointF p2;

 // upper-left point
    if (pointString == "_p1") {
        p1 = leftLine->line().p1();
        p2 = newCenterPos;
        leftLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = topLine->line().p2();
        topLine->setLine(QLineF(p1, p2));
  // upper-right point
    } else if (pointString == "_p2") {
        p1 = topLine->line().p1();
        p2 = newCenterPos;
        topLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = rightLine->line().p2();
        rightLine->setLine(QLineF(p1, p2));
  // lower-right point
    } else if (pointString == "_p3") {
        p1 = rightLine->line().p1();
        p2 = newCenterPos;
        rightLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = bottomLine->line().p2();
        bottomLine->setLine(QLineF(p1, p2));
  // lower-left point
    } else if (pointString == "_p4") {
        p1 = bottomLine->line().p1();
        p2 = newCenterPos;
        bottomLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = leftLine->line().p2();
        leftLine->setLine(QLineF(p1, p2));
    } else {
        return;
    }
}

/////////////////////////////////////////////////////
/* -- comment-in this block to observe problem --  //
/////////////////////////////////////////////////////

protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
    Q_UNUSED(event);
    this->setCursor(Qt::SizeAllCursor);
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
    Q_UNUSED(event);
    this->unsetCursor();
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
    Q_UNUSED(event);
    this->setCursor(Qt::BlankCursor);
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
    Q_UNUSED(event);
    this->unsetCursor();
    this->data(0).toString();
    if (this->isUnderMouse()) {
           this->setCursor(Qt::SizeAllCursor);
    }
}

/////////////////////////////////////////////////////
//       -- end of problem-causing block --        //
///////////////////////////////////////////////////// */

private:
QGraphicsLineItem *topLine;
QGraphicsLineItem *rightLine;
QGraphicsLineItem *bottomLine;
QGraphicsLineItem *leftLine;
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QGraphicsScene scene;

    CustomRectItem *custRect1 = new CustomRectItem(QRectF(30, 30, 10, 10));
    scene.addItem(custRect1);
    custRect1->setData(0, "_p1");

    CustomRectItem *custRect2 = new CustomRectItem(QRectF(70, 30, 10, 10));
    scene.addItem(custRect2);
    custRect2->setData(0, "_p2");

    CustomRectItem *custRect3 = new CustomRectItem(QRectF(70, 70, 10, 10));
    scene.addItem(custRect3);
    custRect3->setData(0, "_p3");

    CustomRectItem *custRect4 = new CustomRectItem(QRectF(30, 70, 10, 10));
    scene.addItem(custRect4);
    custRect4->setData(0, "_p4");

    QGraphicsLineItem *topLine = scene.addLine(QLineF(custRect1->center(), custRect2->center()));
    QGraphicsLineItem *rightLine = scene.addLine(QLineF(custRect2->center(), custRect3->center()));
    QGraphicsLineItem *bottomLine = scene.addLine(QLineF(custRect3->center(), custRect4->center()));
    QGraphicsLineItem *leftLine = scene.addLine(QLineF(custRect4->center(), custRect1->center()));

    custRect1->addLine(leftLine, topLine);
    custRect2->addLine(topLine, rightLine);

    custRect3->addLine(rightLine, bottomLine);
    custRect4->addLine(bottomLine, leftLine);

    QGraphicsView view(&scene);
    view.show();

    return a.exec();
}

compiling the code above you should end up with a small window containing just the QGraphivsView, a Polygon and four Handles attached to the Polygons vertices. Now move a Handle using your mouse. Move it again. Everything should behave as you would expect it from any graphical editor whatsoever. Next, comment-in the Code-Block that reimplements some Mouse Events to basically just change the cursor when hovering over and dragging the handles. Recompile and start again to move a Handle. Moving the very same handle again and... see what happenes! WTF? it jumps back to its initial Position. Does anybody know how to explain this behaviour and how to work around it?

Thanks!

Upvotes: 1

Views: 382

Answers (2)

davepmiller
davepmiller

Reputation: 2708

Make sure to call the base class event after your implementation to ensure that the normal functionality remains.

virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
    this->setCursor(Qt::SizeAllCursor);
    //
    QGraphicsRectItem::hoverEnterEvent( event );
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
    this->unsetCursor();
    //
    QGraphicsRectItem::hoverLeaveEvent( event );

}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
    this->setCursor(Qt::BlankCursor);
    //
    QGraphicsRectItem::mousePressEvent( event );
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
    this->unsetCursor();
    this->data(0).toString();
    if (this->isUnderMouse()) {
           this->setCursor(Qt::SizeAllCursor);
    }
    //
    QGraphicsRectItem::mouseReleaseEvent( event );
}

Upvotes: 2

goug
goug

Reputation: 2444

You need to call the base class implementation for your mousePressEvent and mouseReleaseEvent methods:

QGraphicsRectItem::mousePressEvent (event);

and

QGraphicsRectItem::mouseReleaseEvent (event);

According to the docs, the base implementations handle mouse grabbing, moving, and selection, so you need to call them in this case. I'm a little surprised that the handles move at all, and they clearly are, but the item's position isn't getting handled properly internally.

Upvotes: 0

Related Questions