PDA

View Full Version : QGraphicsItem::setCacheMode - how does it work?



d_stranz
18th May 2012, 01:49
I have a QGraphicsScene with a custom graphics item that can have a very compute-intensive paint() method, depending on the number of points in the data it is fed (basically, it is drawing a number of lines, where the count can get to 7 or 8 million). I tried creating a QPainterPath / QGraphicsPathItem, but I run out of memory with paths of millions of lines. So, I was forced to implement the paint() method.

The problem is, that when I try to use a QRubberBand-derived class to zoom in or otherwise interact with the scene, I get a paint event on the item for every mouse event. For an item that must draw 8 million lines, this is a non-starter, and makes zooming impossible.

I have read other posts which talk about the use of pixmaps to grab widget contents during zoom operations. QGraphicsItem supports pixmap caching, and from the description, it seems that this would do what I want - once the item is initially drawn into the pixmap, subsequent painting is done from the pixmap instead of the paint() method.

In the constructor of my item, I added a call to setCacheMode( QGraphicsItem::DeviceCoordinateCache ). As a result, my paint() method is never called. I have tried adding calls to update() in other places in the code where the item's contents are changed, but nothing ever happens. Comment out the setCacheMode() line in the constructor, everything is painted as usual.

So what is going on here? Are there some preconditions for the use of CacheMode?

Any examples? I've really been beating my head on the wall over this one.

totem
18th May 2012, 09:30
I have tried adding calls to update() in other places in the code where the item's contents are changed, but nothing ever happens.

Did you call prepareGeometryChange() in those places where "the item's contents are changed" ?

d_stranz
18th May 2012, 15:42
Did you call prepareGeometryChange() in those places where "the item's contents are changed" ?

Yes, I am pretty sure it is called, at least by the parent item.

I have one update routine where all changes to the child item are processed, and I know I am calling QGraphicsItem::update() from there. I will also add a prepareGeometryChange() call as well, see if that makes a difference.

d_stranz
31st May 2012, 20:12
OK, I've added a call to prepareGeometryChange() in the main method where all item changes are updated, and have confirmed that it is hit and that the scene sets the item dirty. I left in the existing call to update() for good measure.

Still no paint method call on the item, though. :-( The items that are children of my custom item *are* painted, so I know a paint event is being generated somewhere, but my item's paint() method doesn't get called.

Been beating my head on the wall for too long over this. Anyone have any ideas?

wysota
31st May 2012, 20:36
Please prepare a minimal compilable example reproducing the problem.

d_stranz
31st May 2012, 20:57
That's exactly what I'm now doing. There's way too much code in my plotting class to put that up as an example, so I'll try to write something simpler. If that turns out to work correctly, I'll beat my head on the wall some more until I figure out where the difference lies.

wysota
31st May 2012, 21:54
Subclass QGraphicsRectItem, add some debug messages to this class's paint() method, add an instance of it to your scene and enable caching for it. If paint() gets called after changing the rect of the item, then the blame is in your item code. If it doesn't it's somewhere else (e.g. scene code?).

d_stranz
1st June 2012, 00:12
OK, did this, it works, my original class still doesn't. The good news is that when I rubberband over the new QGraphicsRectItem, its paint() method *isn't* being called, which is exactly what I was trying to achieve in my original class and which I had hoped caching would achieve.

Time to dig into the code and figure out what's going wrong.

wysota
1st June 2012, 00:54
A shortlist to check (as always with graphics items):
1. Is my bounding rect defined correctly (e.g. is it independent of the placement of the item)?
2. Is my shape defined within the bounding rect?
3. Is my paint() routine painting only within the bounding rect?
4. Am I calling prepareGeometryChange() each time the bounging rect is going to change?

d_stranz
1st June 2012, 01:19
1. Is my bounding rect defined correctly (e.g. is it independent of the placement of the item)?

Thank you, thank you. That's where the problem is. My bounding rect was defined in world coordinates, which resulted in a positive width() but negative height(). I have yet to get it right, but at least the item's paint() method is now being called as expected, and caching is doing the right thing when I rubberband.

I owe you a beer or six.

Edit: YES! That was it. Tell me where to send the beer.

wysota
1st June 2012, 09:52
Edit: YES! That was it. Tell me where to send the beer.

Qt Developer Days 2012. Hopefully...