ItemClipsToShape doesn't work



  • Hi,

    I have a custom QGraphicsItem class that paints some complexes figures into scene. I have re-implemented boudingRect() member in order to make suitable "click and drag" on these kind of items. But a QRectF is not enough accurate for the precision that I need in clicks.

    In my QGraphicsItem custom class I have the following sentences:

    @
    this->setFlag(QGraphicsItem::ItemClipsToShape, true);
    this->setFlag(QGraphicsItem::ItemIsMovable, true);
    @

    As I understand, ItemClipsToShape flag should replace the call "boundingRect()" to check if item has been clicked, for "shape" (that returns a QPaintPath) with the shape where I want to detect the click.

    Shape has been implemented correctly, to check it, I draw it and It's properly drawn in scene:
    @
    QPainterPath path = shape();
    painter->drawPath(path); //Properly drawn.
    @

    The problem: it seems like Qt is still calling "boundingRect()" to get the area that I want to use to check if item is clicked, even with the flag set.

    Any suggestions?


  • Moderators

    sry, but reading your post the following is not clear to me: did you reimplement QGraphicsItem::shape() in your graphicsitem subclass?



  • Yes, I did. It returns the shape that I want for click and collision.


  • Moderators

    can you please post the code of the shape() and paint() method



  • Sure:

    It returns the shape. Its a bit complicated method. Some lines build the entire item:

    @
    QPainterPath Cable::shape() const
    QPainterPath result;
    QLineF checkingLine(QPointF(0, 0), QPointF (1, 0));
    foreach (CableLine* course, lines){
    QLineF current(course->posx, course->posy);
    if (current.angleTo(checkingLine) == 0 || current.angleTo(checkingLine) == 180){
    QPointF init(current.p1().x(), current.p1().y() - 3);
    QPointF ending(current.p2().x(), current.p2().y() + 3);
    QRectF rect(init, ending);
    result.addRect(rect);
    continue;
    }
    if (current.angleTo(checkingLine) == 90 || current.angleTo(checkingLine) == 270){
    QPointF init(current.p1().x() - 3, current.p1().y());
    QPointF ending(current.p2().x() + 3, current.p2().y());
    QRectF rect(init, ending);
    result.addRect(rect);
    continue;
    }
    qDebug() << "Error condition";
    }
    result.setFillRule(Qt::OddEvenFill);
    return result;
    }
    @

    And paint:

    @
    void Cable::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {

    if (!painter) return;
    painter->save();
    
    //Draw connection arrow:
    QVector <QPointF> polyPoints;
    CableLine* line = lines.last();
    QLineF last(line->posx, line->posy);
    
    polyPoints.append(QPointF(last.x2() - _ARROW_CABLE_WIDTH/2, last.y2()));
    polyPoints.append(QPointF(last.x2() + _ARROW_CABLE_WIDTH/2, last.y2()));
    polyPoints.append(QPointF(last.x2(), last.y2() + _ARROW_CABLE_HEIGHT));
    QPolygonF poly(polyPoints);
    painter->drawPolygon(poly);
    
    
    painter->restore();
    

    }
    @


  • Moderators

    are you sure you want to use Qt::OddEvenFill fill rule instead of Qt::WindingFill ?
    Nevertheless i couldn't spot any problem in your code on first glance.

    But whats exactly the problem? That boundingRect() is called at all? Or that you receive mouse events even outside the shape?



  • No. The problem is that I want to use shape() instead boundingRect() in order to captura click events.

    I tried with Qt::WindingFill, with the same resutl, and I setted this->setFlag(QGraphicsItem::ItemClipsToShape, true).

    Even so, click event is only called inside the boundingRect() rectangle, but It's not the exactly area that I want the item to reply to such event. It's the shape area intead.

    Shape area is correctly, because when I draw it in paint method, I can see correctly filled and drawn.

    Thank you for you reply.



  • I have some troubles with mapTo.

    When shapes colliding, I enter a function: "collisionProduced". But, by calling mapToScene, the shape seems being displaced to left. How it comes? I just changed the coordinate system in order to obtain the coords in scene system, not moving the shape.



  • I had same problem. My item is a circle icon, the boundingRect is a square. Clicks within the square but outside the circle area triggers mouse events. I fixed it by defining shape() as constant method, which overrides the parent::shape() const instead of overloading another shape().
    @
    QPainterPath shape() const;
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.