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. QGraphicsItem hit detection problem.
Forum Updated to NodeBB v4.3 + New Features

QGraphicsItem hit detection problem.

Scheduled Pinned Locked Moved General and Desktop
10 Posts 3 Posters 3.6k 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.
  • J Offline
    J Offline
    jasonlg3d
    wrote on last edited by
    #1

    I am having an issue where my QGraphicsItem is not alway performing proper hit detection with the mouse. I have subclassed QGrahicsItem and have overridden the shape() method. My shape() method calculates a polygon that surrounds the line. my boudingRect() function calculates a box that completely encloses the line. I have attached two screenshots. The first show the line highlighted in blue, indicating the hover event was fired. The second show the mouse moved just slightly to the right, but still well within the shape() and boundingRect() but the hover event did not fire. Any ideas on what I'm doing wrong?

    I should also note that if I move the endpoints of the line, the hit detection usually starts working normally. It seems somewhat random as to when it breaks.

    Note: The polygon surrounding the line is the shape() and the rectangle around that is the boundingRect()

    !http://i.stack.imgur.com/sfiik.png(Hover working)!
    !http://i.stack.imgur.com/Zy1Wt.png(Hover not working)!

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

      What is the result if you perform a hit detection yourself in the mouseMove event?

      And, to check the obvious, you have called setAcceptHoverEvents(true) for your item?

      1 Reply Last reply
      0
      • J Offline
        J Offline
        jasonlg3d
        wrote on last edited by
        #3

        Yes, setAcceptHoverEvents is true. The hover hit detection works about 80% of the time. It's the random 20% that confuses me.

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

          Do you get the same 20 % when you do the hit detection yourself using shape().contains(mouseEvent->pos()) in the mouseMove event?

          1 Reply Last reply
          0
          • J Offline
            J Offline
            jasonlg3d
            wrote on last edited by
            #5

            I added this:
            @void Connection::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
            if(shape().contains(e->pos()))
            int i = 0;
            }@

            I put a break point at the if statement and it never triggers. It doesnt even trigger when the hover event is working.

            Hover events for reference:
            @void Connection::hoverEnterEvent(QGraphicsSceneHoverEvent *e) {
            m_is_hovering = true;
            update();
            }

            void Connection::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) {
            m_is_hovering = false;
            update();
            }@

            shape and boundingRect for reference:

            @QRectF Connection::boundingRect() const {
            QRectF rect = shape().boundingRect();
            return rect;
            }

            QPainterPath Connection::shape() const {
            QPainterPath path;

            QPointF endpoints[2];
            endpoints[0].setX(0);
            endpoints[0].setY(0);    
            endpoints[1].setX(0);
            endpoints[1].setY(0);
            
            if(m_terms[0] != NULL)
                endpoints[0] = m_terms[0]->scenePos();
            
            if(m_terms[1] == NULL)
                endpoints[1] = *m_end_point;
            else
                endpoints[1] = m_terms[1]->scenePos();
            
            QPointF left_point;
            QPointF right_point;
            
            bool line_is_positive = false;
            // Determine orientation of line
            if(endpoints[0].x() <= endpoints[1].x()) { // 0 is left most point
                left_point = endpoints[0];
                right_point = endpoints[1];
            } else if(endpoints[0].x() > endpoints[1].x()) { // 1 is left most point
                left_point = endpoints[1];
                right_point = endpoints[0];
            } 
            
            if(left_point.y() > right_point.y())
                line_is_positive = true;
            
            QVector<QPointF> points;
            qreal padding = 6.0;
            if(line_is_positive) {
                points.push_back(QPointF(left_point.x() - padding, left_point.y() - padding));
                points.push_back(QPointF(left_point.x() + padding, left_point.y() + padding));
                points.push_back(QPointF(right_point.x() + padding, right_point.y() + padding));
                points.push_back(QPointF(right_point.x() - padding, right_point.y() - padding));
                points.push_back(QPointF(left_point.x() - padding, left_point.y() - padding));
            } else {
                points.push_back(QPointF(left_point.x() - padding, left_point.y() + padding));
                points.push_back(QPointF(left_point.x() + padding, left_point.y() - padding));
                points.push_back(QPointF(right_point.x() + padding, right_point.y() - padding));
                points.push_back(QPointF(right_point.x() - padding, right_point.y() + padding));
                points.push_back(QPointF(left_point.x() - padding, left_point.y() + padding));
            }
            path.addPolygon(QPolygonF(points));
            return path;
            

            }@

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

              My mistake, an item does not normally receive MouseMove events (it receives them only following a MousePressEvent, under conditions specified there).

              For testing purposes, it might serve to put the hit detecting into a mousePress or keyPress event, then trigger that event in cases where the hover hit detection fails (but should not).

              1 Reply Last reply
              0
              • J Offline
                J Offline
                jasonlg3d
                wrote on last edited by
                #7

                I put the check inside the mousePress event. When the line is not hovering, it is also not recieving the mousePress event. Qt thinks that the mouse is not inside the objects shape. However, I'm still drawing the shape and it is clearly correct. :/

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  jasonlg3d
                  wrote on last edited by
                  #8

                  I think the problem is with the boundingRect(). If I understand correctly, Qt is constantly polling the boundingRect() of all of the objects. Then if the mouse is within a boundingRect(), it then polls shape() of that object.

                  I placed a breakpoint in shape(). It does not get called until the mouse enters the boundingRect(). When the hover is not working, the mouse is well within the boundingRect(), but shape is not called.

                  1 Reply Last reply
                  0
                  • J Offline
                    J Offline
                    jasonlg3d
                    wrote on last edited by
                    #9

                    Does the boundingRect() need to have a specific orientation?

                    1 Reply Last reply
                    0
                    • T Offline
                      T Offline
                      theStrict9
                      wrote on last edited by
                      #10

                      I recently encountered the same issue. I didn't know that the boundingRect() was used to trivially reject items, but it makes perfect sense. However, if you don't account for line thickness when computing the boundingRect, then it will have area = 0 when lines/curves are horizontal or vertical and this will cause your QGraphicsItem to be trivially rejected before shape() is hit tested.

                      The solution for me was to implement the shape() function to include thickness plus any additional padding if necessary to make hovering/selection easier (using QPainterPathStroker). Then the boundingRect() implementation just returns shape().boundingRect().

                      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