2

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.

trivelt
  • 1,913
  • 3
  • 22
  • 44
Qvaliz
  • 23
  • 4
  • I've made the simpliest example I could keeping the methods I've used so far to solve this issue. I've pasted it to pastebin (I don't know if I can use it here, so please let me know if it's not how it should be done, it's just that there's a lot of coding to determine positioning and readjustment of the scene): Header files: http://pastebin.com/43Vzkrkq ; C++ files: http://pastebin.com/aLuE5Yg4 ; UI file: http://pastebin.com/1mHWL0hG – Qvaliz Oct 20 '14 at 12:16
  • I suspect the problem lies with the item's boundingRect. Try drawing it in the paint function and see if it is what you expect to see. – TheDarkKnight Oct 20 '14 at 12:53
  • It is, it paints the rect surrounding the 2 items that the arrow is connecting. The thing is that when we add some items on the rightmost part of the grid, the scene expands horizontally, and if we scroll, as soon as the boundingRect center (item's (0,0) ) is out of the view's sight, the entire arrow disappears, and if we scroll until the center is visible again, the entire arrow appears again. What I need is to make the arrow visible all the time, no matter how smallest the visible area is. – Qvaliz Oct 20 '14 at 13:12

2 Answers2

0

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().

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Just did it, the arrows still disappear (I've made it by replacing the path definition from the paint() method to the constructor, and saving it in a variable pre-defined on the arrow.h; the paint method just calls painter->drawPath(«path_variable_name»);). – Qvaliz Oct 20 '14 at 13:31
  • Sounds good - it will be quicker to not have to calculate the object in the paint function. I've updated the answer with your missing a call to prepareGeometryChange. – TheDarkKnight Oct 20 '14 at 14:41
  • They still disappear :( Next I even called update right after calling the prepareGeometryChange(), thinking that it might need to force update of the boundingRect after making changes on the m_boundingRect on the constructor, but with no success. – Qvaliz Oct 20 '14 at 15:22
  • 1
    Display the bounding rect by drawing it in paint, along with its coordinates. As you scroll the view, do the coordinates change? – TheDarkKnight Oct 20 '14 at 15:28
  • I've drawn the boundingRect in paint, painting it in red so I could be able to distinguish it from the rest (I didn't paint the coordinates both because the rect was already painted, as well as I didn't quite understand how I'd paint the coordinates (maybe a QGraphicsTextItem?) ). When I scrolled the view, until the center of the boundingRect was visible, the red rectangle (the boundingRect itself) was fixed (the coordinates stayed the same inside the scene, moving along with it), as soon as the center moved away from the view both the arrows as the red rectangles disappeared. – Qvaliz Oct 20 '14 at 15:54
  • Perhaps it's something in QGraphicsPainterPath that's causing the problem. I recommend simply inheriting from QGraphicsItem and storing a QPainterPath, which you draw in the paint function and still return the painter path in shape(). – TheDarkKnight Oct 20 '14 at 16:00
  • It was :D in the middle of my saga to find what was wrong with this, I've seen in a forum somewhere that when you used a QGraphicsPathItem the boundingRect adjustments were more automated (or something like that, I've been working with Qt for only about 6 months and still don't know lots of stuff) and used it all the way through. Thank you very much ;) P.S.: since the answer is in the comments, can I mark the entire post as answer? It's my first time posting in stackoverflow, so I'm not really sure – Qvaliz Oct 20 '14 at 16:26
  • 1
    I'm missing 7 rep, but as soon as I have them I'll upvote, I really appreciate the time you spent today helping me, many thanks :D – Qvaliz Oct 20 '14 at 16:50
0

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.

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • The problem is that the anchors' position never changes, the only thing that changes is the viewable area of the graphicsView, when the scene's horizontal length is bigger than the view's. – Qvaliz Oct 20 '14 at 13:51
  • even better (easier). Just produce needed path set it set it to `QGraphicsPathItem` and it will work like charm. You don't have paint manually, nor calculating `boundingRect`. – Marek R Oct 20 '14 at 14:17
  • I've tried it and indeed the arrows don't disappear (although the positioning got messed up, but that's a matter of code tweaking), but then I remembered that further in the development of the program I'll need to erase the arrows if I delete an item with arrows connected to it, if I just draw the path, then I won't be able to delete them if they are not items, am I wrong? – Qvaliz Oct 20 '14 at 15:25