Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsObject "Click-jumping" when I want to move the item, and a snap algorithm is present.

QGraphicsObject "Click-jumping" when I want to move the item, and a snap algorithm is present.

Scheduled Pinned Locked Moved Solved General and Desktop
2 Posts 1 Posters 113 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • enjoysmathE Offline
    enjoysmathE Offline
    enjoysmath
    wrote on last edited by enjoysmath
    #1

    Bug demo video:

    https://youtu.be/YLnVWxaOkzo

    Relevant code:

    #include "object.h"
    #include "diagramscene.h"
    #include <QFontMetrics>
    #include <QPointF>
    #include <QGraphicsSceneMouseEvent>
    
    Object::Object(const QString& text)
        : Node(text)
    {
        setFlags(ItemIsSelectable | ItemIsMovable); // | ItemSendsGeometryChanges);
        auto rect = label->boundingRect();
        label->setPos(-rect.center());
    }
    
    //void Object::mousePressEvent(QGraphicsSceneMouseEvent *event) {
    //    offset = event->pos() - computeTopLeftGridPoint(pos());
    //    Node::mousePressEvent(event);
    //}
    
    //void Object::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
    //    Node::mouseMoveEvent(event);
    //}
    
    void Object::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        QPointF newPos = event->scenePos();
        QPointF closestPoint = computeTopLeftGridPoint(newPos);
        setPos(closestPoint);
    }
    
    //QVariant Object::itemChange(GraphicsItemChange change, const QVariant &value)
    //{
    ////    if (change == ItemPositionChange && scene())
    ////    {
    ////        QPointF newPos = value.toPointF();
    ////        QPointF closestPoint = computeTopLeftGridPoint(newPos);
    ////        return closestPoint += offset;
    ////    }
    ////    else
    //    return Node::itemChange(change, value);
    //}
    
    QPointF Object::computeTopLeftGridPoint(const QPointF& pointP)
    {
        int gridSize = dynamic_cast<DiagramScene*>(scene())->gridSize();
        qreal xV = qFloor(pointP.x()/gridSize)*gridSize;
        qreal yV = qFloor(pointP.y()/gridSize)*gridSize;
        return QPointF(xV, yV);
    }
    

    I'm trying to adapt the canonical itemChange-based grid snapping technique to the more UX-friendly way of having the item follow exactly where the cursor is at until you release it, then it snaps. But as you can see I'm failing. It's not clear to me what is causing this growing jump as seen in the video. I've tried about 20 different things to correct it in code. The original itemChange code works, however! It's a mystery.

    So for instance I've already tried adding in offset that was set on mouse press, but which the itemChange would add in. Only resulted in the same bug or worse.

    The default QGraphicsScene move behavior is used - I'm not overriding it and manually setting positions, etc.

    https://github.com/enjoysmath
    https://math.stackexchange.com/users/26327/exercisingmathematician

    1 Reply Last reply
    0
    • enjoysmathE Offline
      enjoysmathE Offline
      enjoysmath
      wrote on last edited by
      #2

      Solution code: =)

      #include "object.h"
      #include "diagramscene.h"
      #include <QFontMetrics>
      #include <QPointF>
      #include <QGraphicsSceneMouseEvent>
      
      Object::Object(const QString& text)
          : Node(text)
      {
          setFlags(ItemIsSelectable | ItemIsMovable); // | ItemSendsGeometryChanges);
          auto rect = label->boundingRect();
          label->setPos(-rect.center());
      }
      
      //void Object::mousePressEvent(QGraphicsSceneMouseEvent *event) {
      //    offset = event->pos() - computeTopLeftGridPoint(pos());
      //    Node::mousePressEvent(event);
      //}
      
      void Object::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
          setPos(event->scenePos());
      }
      
      void Object::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
      {
          QPointF newPos = pos();
          QPointF closestPoint = closestGridPoint(newPos);
          setPos(closestPoint);
      }
      
      //QVariant Object::itemChange(GraphicsItemChange change, const QVariant &value)
      //{
      ////    if (change == ItemPositionChange && scene())
      ////    {
      ////        QPointF newPos = value.toPointF();
      ////        QPointF closestPoint = computeTopLeftGridPoint(newPos);
      ////        return closestPoint += offset;
      ////    }
      ////    else
      //    return Node::itemChange(change, value);
      //}
      
      QPointF Object::closestGridPoint(const QPointF& pointP)
      {
          int gridSize = dynamic_cast<DiagramScene*>(scene())->gridSize();
          qreal xV = qRound(pointP.x()/gridSize)*gridSize;    // BUGFIX: use qRound instead of qFloor here
          qreal yV = qRound(pointP.y()/gridSize)*gridSize;
          return QPointF(xV, yV);
      }
      

      https://github.com/enjoysmath
      https://math.stackexchange.com/users/26327/exercisingmathematician

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved