Nominate our 2022 Qt Champions!

QGraphicsView Rubberband Selection mode problem

  • Hello everyone,

    I'm having trouble using custom QGraphicsView and QGraphicsItem.
    Here are the two overwritten method of my QGraphicsItem :

    QRectF Node::boundingRect() const
        //extraBorder to prevent graphic artifacts when moving nodes
        qreal extraBorder = 200.f;
        //return QRect();
        return QRectF(-m_width/2.f - m_borderSize - extraBorder,
                      -m_height/2.f - m_borderSize - extraBorder,
                      m_width + 2.f*m_borderSize + 2.f*extraBorder,
                      m_height + 2.f*m_borderSize + 2.f*extraBorder);
    QPainterPath Node::shape() const
        QPainterPath path;
        if(m_shape == Rectangle)
            path.addRect(-m_width/2.f - m_borderSize, -m_height/2.f - m_borderSize, m_width + 2.f*m_borderSize, m_height + 2.f*m_borderSize);
        else if(m_shape == Ellipse)
            path.addEllipse(-m_width/2.f - m_borderSize, -m_height/2.f - m_borderSize, m_width + 2.f*m_borderSize, m_height + 2.f*m_borderSize);
        return path;

    Basically, Nodes are custom QGraphicsItem that can be have several shapes. Here are my two problems :

    1. If you look at the boundingRect method, you'll see that I added an extraborder to the rect. I did that because when I was moving my object too fast in the view, a part of the Node was not showing for a brief moment (until I stopped moving the node actually. This problem can be reproduced in the diagramscene example supplied with Qt Creator. However, I had to overwrite the shape method in order to supply the real shape (selection purpose). I supposed the problem was coming from the fact when a moving a node, only its bounding rect was being redrawn. Is there a better way to fix this "issue" ?

    2. When using simple selection by click, everything is working as I want. However, I want to use rubberband to allow simple selection of multiple nodes. The default mode, IntersectsItemShape, works fine but I'd like to select my items only if they are fully contained in my rubberband. Then I used ContainsItemShape mode :

    DiagramView::DiagramView(QGraphicsScene * scene, QWidget * parent) :
        QGraphicsView(scene, parent)

    But then, it behaves like the ContainsItemBoundingRect mode : the nodes are only selected if the rect with extra border is contained, it seems like it totally ignores the shape...

    Am I doing something wrong, or is this a bug ?

    1. Your paint code would be useful. The bounding rect must contain all pixels which are painted, including all pens. This can get tricky in case of thick cosmetic pens.
    2. The following bug might be of interest:

    1. Thank you for your answer. Here is the paint code :
    void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        painter->setRenderHint(QPainter::Antialiasing, true);
        QPainterPath path;
        //by default, border is drawn outside and inside the shape (at the middle), that's why we adjust the shapes size with m_borderSize
        if(m_shape == Rectangle)
            path.addRect(-m_width/2.f - m_borderSize/2.f, -m_height/2.f - m_borderSize/2.f, m_width + m_borderSize, m_height + m_borderSize);
        else if(m_shape == Ellipse)
            path.addEllipse(-m_width/2.f - m_borderSize/2.f, -m_height/2.f - m_borderSize/2.f, m_width + m_borderSize, m_height + m_borderSize);
        QPen pen(m_borderColor, (int)m_borderSize);
        painter->fillPath(path, m_color);
    1. Indeed, it seems to be the same bug. So, do I need to open a new bug or maybe directly contact the dev team ?

  • So you paint a rect with a total width of m_width + m_borderSize.
    You use a pen of width m_borderSize.
    So the rectangle paints extra pixels to the left (half m_borderSize) and right (m_borderSize). You have to account for these pixels in the boundingRect().

    BTW your code between shape and paint pretty much looks the same. You might want to merge those codes.

  • I suppose your answer is for point 1.
    Looking at my boundingRect() method, I think I already take into account the bordersize.

    The problem I described is hard to explain, but you can easily reproduce it by opening the diagramscene example supplied with Qt Creator : when you select a node in your scene and that you move it fast with the mouse, you can observe for a brief moment that a part of the node is not drawn (the entire node is drawn when you stop moving it fast).

    Do you manage to observe this ? If yes, how to correct it ?

    1. I don't really see what you mean in the DigramScene example. But it might just be due to different expectations. Is there a GraphicsView example where things paint "correctly", for comparison?

    Regarding your boundingRect code, let's see with a specific example:
    Let's say m_width is 20, and m_borderSize is 5
    The path.addRect would add a rectangle with:
    Left: -12.5
    Width: 25.0

    Because the pen is 5 pixels wide, the left rectangle line would start at -15.0 and paint to -10.0. The right line would paint from 10.0 to 15.0.

    So your boundingRect would need at least
    Left: -15.0
    Width: 30.0

    Well, of course, your extra border provides that, but I understood your question to be why you need that. Here is the answer: If you add the border once for painting, you need to add it twice for the bounding rect, because your pen gives you that extra width on painting.

    Regarding the bug, your options depend on whether you are a commercial license holder: If so, I recommend contacting Qt support about it, and ask them to fix that bug. Don't expect a quick fix in an official Qt version, but you can expect a workaround or a piece of code that allows you to build your own fixed Qt version.
    In any case, the bug is marked as "Need more info". If you can provide that info, devs may decide to pursue it further.
    Don't count on it - GraphicsView is no longer a first class citizen in Qt.

Log in to reply