Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
qtws26_logo

The Qt Event of the Year: Qt World Summit 2026

Save Your Spot >
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsView::itemAt() - How to correctly pick QGraphicsItem?
Qt 6.12 LTS is out! See what's new in the release blog

QGraphicsView::itemAt() - How to correctly pick QGraphicsItem?

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 2 Posters 2.8k Views 1 Watching
  • 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.
  • A Offline
    A Offline
    Asperamanca
    wrote on last edited by
    #2

    Seems you are mixing coordinate systems.
    boundingRect is in 'item' coordinates. That doesn't tell you the item's position within the scene.
    Map the boundingRect to scene coordinates using QGraphicsItem::mapToScene, then you can compare it the the scene coordinates of your mouse position

    T 1 Reply Last reply
    2
    • A Asperamanca

      Seems you are mixing coordinate systems.
      boundingRect is in 'item' coordinates. That doesn't tell you the item's position within the scene.
      Map the boundingRect to scene coordinates using QGraphicsItem::mapToScene, then you can compare it the the scene coordinates of your mouse position

      T Offline
      T Offline
      tomas.soltys
      wrote on last edited by
      #3

      @Asperamanca thanks for your reply. When I map to scene it gets only more obvious that something is oddly wrong.

      void DiagramView::mousePressEvent(QMouseEvent *mouseEvent)
      {
          if (QGraphicsItem *item = this->itemAt(mouseEvent->pos()))
          {
              qDebug() << "Hit " << mouseEvent->pos() << mapToScene(mouseEvent->pos()) << item->mapToScene(item->boundingRect());
          }
          else
          {
              qDebug() << "Miss" << mouseEvent->pos() << mapToScene(mouseEvent->pos());
          }
      }
      

      Output:

      Miss QPoint(680,423) QPointF(267,-3)
      Hit  QPoint(679,426) QPointF(266,0)  QPolygonF(QPointF(250,0)QPointF(380,0)QPointF(380,54)QPointF(250,54)QPointF(250,0))
      Hit  QPoint(679,430) QPointF(266,4)  QPolygonF(QPointF(250,0)QPointF(380,0)QPointF(380,54)QPointF(250,54)QPointF(250,0))
      Hit  QPoint(675,450) QPointF(262,24) QPolygonF(QPointF(250,0)QPointF(380,0)QPointF(380,54)QPointF(250,54)QPointF(250,0))
      Miss QPoint(675,451) QPointF(262,25)
      

      I actually happens for any item at any position exactly same. As if the view/scene was able to "see" only part of the item, as if it was down-scaled scaled and keeping its origin.

      I paint the rectangle in following way:

      painter->drawRoundedRect(QRectF(0,0,130,54),5,5);
      setPos(250,0);
      
      1 Reply Last reply
      0
      • A Offline
        A Offline
        Asperamanca
        wrote on last edited by
        #4

        How do you set the boundingRect?
        Does the item have a shape as well?

        itemAt primarily uses shape(), boundingRect() is only a fallback if shape is not set.

        T 1 Reply Last reply
        0
        • A Asperamanca

          How do you set the boundingRect?
          Does the item have a shape as well?

          itemAt primarily uses shape(), boundingRect() is only a fallback if shape is not set.

          T Offline
          T Offline
          tomas.soltys
          wrote on last edited by
          #5

          @Asperamanca

          QRectF GraphicsNodeItem::boundingRect() const
          {
              return QRectF(0,0,130,54).normalized();
          }
          
          QPainterPath GraphicsNodeItem::shape() const
          {
              QPainterPath path;
              path.addRect(this->boundingRect());
              return path;
          }
          

          Even if I set bounding rectangle to some ridiculous size itemAt() will always return item only if clicked within small rectangle originating in the top left corner of the bounding rectangle.

          A 1 Reply Last reply
          0
          • T tomas.soltys

            @Asperamanca

            QRectF GraphicsNodeItem::boundingRect() const
            {
                return QRectF(0,0,130,54).normalized();
            }
            
            QPainterPath GraphicsNodeItem::shape() const
            {
                QPainterPath path;
                path.addRect(this->boundingRect());
                return path;
            }
            

            Even if I set bounding rectangle to some ridiculous size itemAt() will always return item only if clicked within small rectangle originating in the top left corner of the bounding rectangle.

            A Offline
            A Offline
            Asperamanca
            wrote on last edited by
            #6

            @tomas-soltys
            That looks weird. What version of Qt are you using?
            Can you try the behavior with a stock QGraphicsRectItem, using the setRect function to set your "boundingRect"?

            T 1 Reply Last reply
            0
            • A Asperamanca

              @tomas-soltys
              That looks weird. What version of Qt are you using?
              Can you try the behavior with a stock QGraphicsRectItem, using the setRect function to set your "boundingRect"?

              T Offline
              T Offline
              tomas.soltys
              wrote on last edited by tomas.soltys
              #7

              @Asperamanca

              QGraphicsRectItem works nicely.

              QGraphicsRectItem *rectItem = new QGraphicsRectItem;
              rectItem->setRect(0, 0, 130, 54);
              rectItem->setPos(250,0);
              

              Qt version is 6.3.1 and I am experiencing this behavior on Linux, MacOS and Windows.

              1 Reply Last reply
              0
              • A Offline
                A Offline
                Asperamanca
                wrote on last edited by
                #8

                @tomas-soltys said in QGraphicsView::itemAt() - How to correctly pick QGraphicsItem?:

                GraphicsNodeItem

                Your code for boundingRect and shape is pretty much identical to the code of QGraphicsRectItem (ignoring the extras that are needed when using a pen as border).
                Is your GraphicsNodeItem a base class? Could boundingRect() be overloaded and thus behave differently?

                T 1 Reply Last reply
                0
                • A Asperamanca

                  @tomas-soltys said in QGraphicsView::itemAt() - How to correctly pick QGraphicsItem?:

                  GraphicsNodeItem

                  Your code for boundingRect and shape is pretty much identical to the code of QGraphicsRectItem (ignoring the extras that are needed when using a pen as border).
                  Is your GraphicsNodeItem a base class? Could boundingRect() be overloaded and thus behave differently?

                  T Offline
                  T Offline
                  tomas.soltys
                  wrote on last edited by
                  #9

                  @Asperamanca

                  Yes it is a base class.

                  class GraphicsNodeItem : public QGraphicsItem
                  {
                  
                      public:
                  
                          GraphicsNodeItem(QGraphicsItem *parent = nullptr);
                          QRectF boundingRect() const override;
                          QPainterPath shape() const override;
                  };
                  
                  class GraphicsPersonItem : public GraphicsNodeItem
                  {
                      public:
                  
                          explicit GraphicsPersonItem(const FPerson &person, GraphicsNodeItem *parent = nullptr);
                          void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
                  };
                  

                  I have noticed that GraphicsNodeItem::shape() is called only when successful hit, whereas GraphicsNodeItem::boundingRect() is being called constantly. Is this correct behavior?

                  A 1 Reply Last reply
                  0
                  • T tomas.soltys

                    @Asperamanca

                    Yes it is a base class.

                    class GraphicsNodeItem : public QGraphicsItem
                    {
                    
                        public:
                    
                            GraphicsNodeItem(QGraphicsItem *parent = nullptr);
                            QRectF boundingRect() const override;
                            QPainterPath shape() const override;
                    };
                    
                    class GraphicsPersonItem : public GraphicsNodeItem
                    {
                        public:
                    
                            explicit GraphicsPersonItem(const FPerson &person, GraphicsNodeItem *parent = nullptr);
                            void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
                    };
                    

                    I have noticed that GraphicsNodeItem::shape() is called only when successful hit, whereas GraphicsNodeItem::boundingRect() is being called constantly. Is this correct behavior?

                    A Offline
                    A Offline
                    Asperamanca
                    wrote on last edited by
                    #10

                    @tomas-soltys
                    I think boundingRect is called first, if that indicates a hit, the shape is checked.

                    So if you click far outside of a circle, the click is outside of it's boundingRect and shape() is not called.
                    If you click into the center of the circle, boundingRect indicates a hit, and shape confirms it.
                    If you click at the corner of the circle, the click may be inside the boundingRect, but outside of the shape.

                    T 1 Reply Last reply
                    0
                    • A Asperamanca

                      @tomas-soltys
                      I think boundingRect is called first, if that indicates a hit, the shape is checked.

                      So if you click far outside of a circle, the click is outside of it's boundingRect and shape() is not called.
                      If you click into the center of the circle, boundingRect indicates a hit, and shape confirms it.
                      If you click at the corner of the circle, the click may be inside the boundingRect, but outside of the shape.

                      T Offline
                      T Offline
                      tomas.soltys
                      wrote on last edited by tomas.soltys
                      #11

                      @Asperamanca
                      I have found working solution. Since size of my item depends on QFontMetrics used by QPainter I am setting final dimensions inside GraphicsPersonItem::paint() method. Once I added this->prepareGeometryChange(); at the beginning my picking started to work correctly.

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        Asperamanca
                        wrote on last edited by
                        #12

                        If possible, calculate the geometry before paint, e,g. when setting text and font. This will save you an extra paint cycle.

                        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
                        • Unsolved