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. Click & drag a QGraphicsItem inside QGraphicsScene?

Click & drag a QGraphicsItem inside QGraphicsScene?

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 917 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.
  • L Offline
    L Offline
    LiberRexPaimon
    wrote on last edited by
    #1

    I'm having some confusion with clicking and dragging of a QGraphicsItem inside a QGraphicsScene. I'd like to implement the functionality that:

    • a single click in an empty part of the scene adds an item
    • a single click on an existing item removes this item.
    • a click and mouse move action drags the item around

    I've currently tried to implement this with a mouseReleaseEvent for my custom scene implementation:
    For my QGraphicsItem called Node I set:

    Node::Node(QPointF pos) :
        QGraphicsItem()
    {
        setFlag(QGraphicsItem::ItemIsSelectable);
        setFlag(QGraphicsItem::ItemIsMovable);
        setFlag(QGraphicsItem::ItemSendsGeometryChanges);
        setPos(pos);
    }
    

    As expected, I can now drag my items around the scene. However, for add and remove functionality I'm trying this approach by overriding scene methods:

    void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
        if (mouseEvent->button() == Qt::LeftButton){
            QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
            Node *node = qgraphicsitem_cast<Node *>(item);
            if(node){
                removeItem(node);
            }else{
                QPointF pt = mouseEvent->scenePos();
                Node* node = new Node(pt);
                addItem(node);
            }
        }
        QGraphicsScene::mouseReleaseEvent(mouseEvent);
    }
    
    

    However, the user clicking and dragging currently also leads to the item being removed, since click and drag triggers a mouseReleaseEvent event too. How can I detect if the item is being dragged around the scene to catch this special case and not trigger a delete? Is there perhaps a better approach to this in general?

    I've checked for dragging tutorials, but somehow everything I find is associated with inter-application drag and drop & mimedata which is not what I'm after.

    JonBJ Pl45m4P 2 Replies Last reply
    0
    • L LiberRexPaimon

      I'm having some confusion with clicking and dragging of a QGraphicsItem inside a QGraphicsScene. I'd like to implement the functionality that:

      • a single click in an empty part of the scene adds an item
      • a single click on an existing item removes this item.
      • a click and mouse move action drags the item around

      I've currently tried to implement this with a mouseReleaseEvent for my custom scene implementation:
      For my QGraphicsItem called Node I set:

      Node::Node(QPointF pos) :
          QGraphicsItem()
      {
          setFlag(QGraphicsItem::ItemIsSelectable);
          setFlag(QGraphicsItem::ItemIsMovable);
          setFlag(QGraphicsItem::ItemSendsGeometryChanges);
          setPos(pos);
      }
      

      As expected, I can now drag my items around the scene. However, for add and remove functionality I'm trying this approach by overriding scene methods:

      void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
          if (mouseEvent->button() == Qt::LeftButton){
              QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
              Node *node = qgraphicsitem_cast<Node *>(item);
              if(node){
                  removeItem(node);
              }else{
                  QPointF pt = mouseEvent->scenePos();
                  Node* node = new Node(pt);
                  addItem(node);
              }
          }
          QGraphicsScene::mouseReleaseEvent(mouseEvent);
      }
      
      

      However, the user clicking and dragging currently also leads to the item being removed, since click and drag triggers a mouseReleaseEvent event too. How can I detect if the item is being dragged around the scene to catch this special case and not trigger a delete? Is there perhaps a better approach to this in general?

      I've checked for dragging tutorials, but somehow everything I find is associated with inter-application drag and drop & mimedata which is not what I'm after.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @LiberRexPaimon said in Click & drag a QGraphicsItem inside QGraphicsScene?:

      • a single click on an existing item removes this item.
      • a click and mouse move action drags the item around

      I was about to say: they are both mouse downs followed by mouse ups. A notable difference is that for a click the up happens at around the same place as the down but for a drag it happens at another position. So note where the mouse down occurred and compare the position of the corresponding mouse up to see the distance. When I came across just this advice at https://doc.qt.io/qt-5/dnd.html#dragging:

      For widgets that need to distinguish between mouse clicks and drags, it is useful to reimplement the widget's mousePressEvent() function to record to start position of the drag:
      ...
      This particular approach uses the QPoint::manhattanLength() function to get a rough estimate of the distance between where the mouse click occurred and the current cursor position. This function trades accuracy for speed, and is usually suitable for this purpose.

      Have a look at the discussion and code there. It's for widgets but I assume the same principle holds for QGraphicsItem/Scene.

      1 Reply Last reply
      2
      • L LiberRexPaimon

        I'm having some confusion with clicking and dragging of a QGraphicsItem inside a QGraphicsScene. I'd like to implement the functionality that:

        • a single click in an empty part of the scene adds an item
        • a single click on an existing item removes this item.
        • a click and mouse move action drags the item around

        I've currently tried to implement this with a mouseReleaseEvent for my custom scene implementation:
        For my QGraphicsItem called Node I set:

        Node::Node(QPointF pos) :
            QGraphicsItem()
        {
            setFlag(QGraphicsItem::ItemIsSelectable);
            setFlag(QGraphicsItem::ItemIsMovable);
            setFlag(QGraphicsItem::ItemSendsGeometryChanges);
            setPos(pos);
        }
        

        As expected, I can now drag my items around the scene. However, for add and remove functionality I'm trying this approach by overriding scene methods:

        void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
            if (mouseEvent->button() == Qt::LeftButton){
                QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
                Node *node = qgraphicsitem_cast<Node *>(item);
                if(node){
                    removeItem(node);
                }else{
                    QPointF pt = mouseEvent->scenePos();
                    Node* node = new Node(pt);
                    addItem(node);
                }
            }
            QGraphicsScene::mouseReleaseEvent(mouseEvent);
        }
        
        

        However, the user clicking and dragging currently also leads to the item being removed, since click and drag triggers a mouseReleaseEvent event too. How can I detect if the item is being dragged around the scene to catch this special case and not trigger a delete? Is there perhaps a better approach to this in general?

        I've checked for dragging tutorials, but somehow everything I find is associated with inter-application drag and drop & mimedata which is not what I'm after.

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by
        #3

        @LiberRexPaimon said in Click & drag a QGraphicsItem inside QGraphicsScene?:

        void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
        if (mouseEvent->button() == Qt::LeftButton){
        QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
        Node *node = qgraphicsitem_cast<Node >(item);
        if(node){
        removeItem(node);
        }else{
        QPointF pt = mouseEvent->scenePos();
        Node
        node = new Node(pt);
        addItem(node);
        }
        }
        QGraphicsScene::mouseReleaseEvent(mouseEvent);
        }

        In addition to what @JonB said:
        This implementation would remove nodes, even when you click and drag another node and only release the mouse button over an existing node. So I would add some check whether the node on which the mouse button was released, was pressed (mouse down) before. Therefore you could add a bool clicked to your Node class and check if it's true before removing the item from your scene to ensure that it is the correct item that was meant to be removed.


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        1 Reply Last reply
        2

        • Login

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