I would like to know whether it is possible to shift part of a drawing by copying its pixels rather than redrawing it.
I work in an embedded environment, where performance is a key factor. We use Qt 4.8.
I have a set of real-time data points that I want to draw. I define the following class:
class SetOfDataPoints : public QGraphicsItem
{
public:
<constructor>
QRectF boundingRect() const { ... }
void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget = NULL) { ... }
<other methods>
};
At regular intervals, I read a new data point, add it to the instance of SetOfDataPoints
, and shift the SetOfDataPoints
to the left (by calling QGraphicsItem::moveBy()
on the SetOfDataPoints
), so the new data point becomes visible. As a result, SetOfDataPoints::paint()
gets called, and in that method I have to draw the entire set of data points. The drawing currently consists only of line segments that connect the data points, but will become more elaborate in the future.
Now, it feels inefficient to redraw the whole set of data points, when most of the graph is actually just shifted to the left. I would like to shift the pixels of the unchanged part of the graph to the left, and draw only the one line segment that connects the last two points. At least I would like to try, and measure how much that improves performance.
Is there a way to do that in Qt 4.8?
This won't work in general:
Your item doesn't exist as any pixels until it's rendered. You don't know how many pixels it is drawn on, or even if there are any, since there are 0 or more views your scene is shown on, and the item might be visible to various extent on these views.
There are transformations applied to your item. It doesn't have to be rectangular.
Your item is composited with the items below it, unless it is completely opaque.
Your item, shown on a view, is composited with the backing store of the widget the view is on.
You can optimize for special cases. If your item is not cached, then it's always painted on a view, and the widget
argument of paint will point to that widget. You then have direct access to the backing store, and the painter gives you the transformation used to go from item coordinates to the backing store's device coordinates. You can then inspect the path on the widget tree from the view to the window for opacity. If all intervening widgets paint opaque, and your item has an orientation-preserving transformation, you can certainly do a blit on the image, and redraw only a small part of the item.
If your item is cached, it should then be cached in device coordinates. You can do the blitting too, as you're painting on a pixmap. That pixmap is then composited onto the backing store of the window the view is on. There's a separate cache pixmap for each view.
When blitting, you must always recognize how much of the previous pixels are correct. For each view or cache pixmap, you should keep a region that is valid. That region initally should be empty.