Should QGraphicsItem::boundingRect() include child bounding rects? - c++

Googling suggests that it should.
But the dragdroprobot example implementation (on the parent Robot object) suggests not:
QRectF Robot::boundingRect() const
{
return QRectF();
}
Which is correct, or is there something more subtle going on?

Child items are painted directly by the scene not by the parent, and according to the documentation about boundingRect():
QGraphicsView uses this to determine whether the item requires redrawing.
So, if there is no drawing to do in the parent, there is no need to return a non-null bounding rectangle, even if the parent has child items.
And if there is some drawing in the parent, it only needs to contain its own bounding rectangle.

Under normal usage the children of your QGraphicsItem are contained within its bounding rect, but depending on your implementation I don't believe that this is required.
If you need the bounding rect of an item's children you can simply use
QGraphicsItem::childrenBoundingRect();

Possibly related:
QGraphicItemGroup is different.
The documentation says:
The boundingRect() function of QGraphicsItemGroup returns the bounding rectangle of all items in the item group.
(However, the documentation does not say that boundingRect is reimplemented, although QGraphicsItemGroup inherits QGraphicsItem. Thats probably a flaw in the documentation.)
QGraphicItem.shape() seems to be similar to boundingRect() in that the view calls it for each instance (for purposes of picking i.e. QGraphicsView.items(), similarly as boundingRect() is called for purposes of determining what needs to be redrawn).
As far as I can tell, QGraphicItemGroup.shape() is never called by QGraphicsView.items(). The documentation does not say that it is reimplemented.

Related

Restrict movement area of QGraphicsItem inside of polygon area

I am trying to limit the movement of QGraphicsItem inside of a parent object inherited from QGraphicsPathItem that has an arbitrary complex shape (not square).
As I understand, I should extract each point of the moving object and check whether each of them is not contained in the parent QPainterPath. Then split the parent QPainterPath into small rectangle-shaped polygons and restrict movement area in the bounding box of each sub polygon.
So, I would like to know if there are any other options to exist. Thanks.
Maybe you can check on QGraphicsItem move event if it is still inside QGraphicsPathItem.
The check itself, you can do it with this QGraphicsItem method:
bool QGraphicsItem::collidesWithItem(const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
And to be sure that item is still fully enclosed inside its parent, set the mode to Qt::ContainsItemShape
If it is false, return QGraphicsItem to its previous position
EDIT: this check returns if QGraphicsItems shape is inside other QGraphicsItems shape, not its bounding box.

Qt: Custom QGraphicsItem not showing when boundingRect() center is out of view

I'm making a Diagram (Fluxogram) program and for days I'm stuck with this issue:
I have a custom QGraphicsScene that expands horizontally whenever I place an item to it's rightmost area. The problem is that my custom arrows (they inherit QGraphicsPathItem) disappear from the scene whenever it's boundingRect() center is scrolled off the view. Everytime the scene expands, both it's sceneRect() and the view's sceneRect() are updated as well.
I've:
set ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate)
the item flags QGraphicsItem::ItemIgnoresTransformations and QGraphicsItem::ItemSendsGeometryChanges, setActive(true) on the item as well, and everytime I add an arrow to the scene i call the update(sceneRect()) method. Still, everytime I scroll the view, as soon as the arrow's boundingRect() center moves away from the view, all the arrow disappears. If I scroll back and the boundingRect() center enters the view, all the arrow appears again.
Can someone give me a tip of what I might be missing? I've been using Qt's example project diagramscene as reference, so a lot of my code is similar (the "press item toolButton -> click on the scene" relation to insert items, the way they place the arrows to connect the objects,...).
In the meanwhile I'll try to make a minimal running example that can show what my issue is.
Your Arrow object inherits from QGraphicsPathItem, which I expect also implements the QGraphicsItem::shape function.
Override the shape function in your Arrow class, to return the shape of the item. This, along with the boundingRect is used to collision detection and detection of an item on-screen.
In addition, before changing the shape of an item by changing its boundingRect, you need to call prepareGeometryChange.
As the docs state: -
Prepares the item for a geometry change. Call this function before changing the bounding rect of an item to keep QGraphicsScene's index up to date.
So, in the Arrow class, store a QRectF called m_boundingRect and in the constructor: -
prepareGeometryChange();
m_boundingRect = QRectF(-x, -y, x*2, y*2);
Then return m_boundingRect in the boundingRect() function.
If this is still an issue, I expect it's something in QGraphicsPainterPath that's causing the problem, in which case, you can simply inherit from QGraphicsItem and store a QPainterPath with which you draw in the item's paint function and also return the painter path in shape().
You are making your life too complicated. Do not subclass QGraphicsPathItem just use it and update its path value every time position of anchors (from to) changes.

How to clear existing content before redrawing QGraphicsItem?

I have a drawing that is built inside a QGraphicsScene with several layers of QGraphicsItem derived objects.
I am repositioning the QGraphicsItem objects based on some parameters and have noticed that there are some "ghost" trails left unless I call graphicsArea->viewport()->update(). I am repositioning the QGraphicsItem objects quite frequently (i.e. when a slider is moved) and updating the viewport only works if I call it manually some time after drawing is finished (e.g. on a button click).
One possible solution that I found was to fill the background of each QGraphicsItem to be a neutral colour. This doesn't work when I have overlapping items though, as the underlying items can get overwritten.
Does anyone have any suggestions?
Thanks,
Alan

how to get non topmost qgraphicsitem from the scene

Excuse me if so topic is also created. I have look for it and, regardless, not found one.
Can I get qgraphicsitem by click coordinates that is just beneath the topmost item by cute small way? I mean I can try to use this fact that scene sends click-signal to all items beneath the cursor position, but it seems like unnecessary complication.
Use QGraphicsView::items(const QPoint& pos) const to return all the items under a viewport coordinate, they are in descending stacking order (docs).

Drawing areas and expose events

I have a dialogue which contains a drawing area. I wish to redraw the contents of the drawing area if the dialogue is enlarged or shrunk or buried and exposed, as is normal and natural with drawing areas. To this end, I created a method
bool on_expose_event (GdkEventExpose *event);
in the class. But the presence of this event stops all the other widgets on the dialogue from being drawn correctly; presumably it is also being invoked when they are exposed. How do I create a function to refresh the drawing area only, and leave all the other widgets to take care of themselves?
You should really sub-class the Gtk::DrawingArea class and implement the on_expose_event() function from that class.