PDA

View Full Version : GraphicsView: how to avoid animated background when animating sceneRect



NameZero912
18th August 2012, 17:53
Hi,

I'm using the GraphicsView framework to realize a custom 2D GUI. I created the different menu screens in Photoshop, and separately exported the background image on the one hand, and transparent (PNG) images that I place in the different menu screens on the other hand. Each of my menu screen is realized by a class I created, which extends QGraphicsObject. In the QGraphicsView, where I setup the QGraphicsScene, I call
QGraphicsScene::setBackgroundBrush() on it to set the background image.

Since I want menu transitions in the "swipe left/right" fashion (i.e. one menu flies out of the view, e.g. to the left, and the next menu flies into the view from the right), I decided to arrange all the menus (QGraphicsObjects) spatially in the QGraphicsScene next to each other. Using the State machine framework and animations framework, I have one state per menu screen, and I'm assigning the QGraphicsView's sceneRect property to a QRectF for each state independently.

Generally this approach works, and I get smooth menu-to-menu transitions. However, the transitions do not look right. What I want (expect) is that the background image always stays static, "as it is" (regardless that sceneRect is animated), i.e. I'd expect that only the transparent parts of my menu screens are "flying" in/out of the view from the left/right. However, unforunately the background itself does also move, i.e. it is as if QT has taken a screenshot of the view right at the start, and one at the end of the animation, and then animate between the two screenshots.

Is there a way I can force the background to be completely static anyways?

Cheers!

ecanela
19th August 2012, 01:18
i cant complete visualize you problem. maybe some screenshot or even better the minimal source code who reproduce your problem.

meanwile you maybe try some one of this options
- draw background in the view not the scene. set QGrapicsView::setBackgroundBrush(),
- reimplement QGraphicsView::drawBackground() this provide more control over how painting the background

d_stranz
19th August 2012, 01:48
You might also try one of the caching options on the QGraphicsItem that holds the images. This was vital in my app to allow smooth rubber banding over a complex background graphic. Using caching on the graphic meant that it would only be physically redrawn when the content or size changed; all the rest of the time it was simply blitted from the cache, with no noticeable flicker at all.

NameZero912
19th August 2012, 11:49
Hi. Generally what I want to achieve is that the drawn background image sticks to the "animated camera" (if you agree on calling the animation of QGraphicsView's sceneRect as animating a camera view).
A visualization of my problem:
Below you see, in this order, the first menu screen, the second menu screen, and the bad transition I get from the first to the second menu screen. It looks bad because in the transition the background is also moving, even though it really shouldn't. It seems that QT actually replicates/tiles the background image over the complete scene.
813381348135

Changing to set the backgroundBrush on the QGraphicsView rather than the QGraphicsScene did unfortunately not have any effect (problem remains the same).

Regarding caching:
In my QGraphicsview I use:

setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);
setViewportUpdateMode(FullViewportUpdate);
setCacheMode(CacheBackground);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
Disabling the CacheBackground does not fix the problem either, but decreases performance significantly.

Regarding the items I place in the scene (i.e. the menu screens), I use
setCacheMode(QGraphicsItem::DeviceCoordinateCache)
I'm quite reluctant to touch (override) the drawBackground(), basically because I've already tried before (when I was tinkering how to make sure the view always scales with my viewport, which I solved via fitInView(scene()->sceneRect(), Qt::IgnoreAspectRatio) at last). And I did not have much success in understanding what the parameters are, or, basically how to draw the background correctly.

Added after 28 minutes:

This (https://bugreports.qt-project.org/browse/QTBUG-7079) (click me) got me close to the solution of my problem. However, the background image is not correctly scaled. My current solution to this scaling problem is that inside the drawBackground method, I replace the drawPixmap() call with
painter->drawPixmap(old.mapRect(rect), backgroundImage.scaled(viewport()->width(), viewport()->height()), old.mapRect(rect));
While this works, I discovered that drawBackground() is called ca. 30 times during a transition from one screen to the next, and once I'm full screen (and at high resolution) this causes harsh performance drops. Why does QT have to redraw the background constantly during a transition? How can I avoid that (Note: background cache is already enabled, otherwise drawBackground would be called ALL the time)? I somehow need to be able to paint the rescaled background into some kind of buffer which does not require to be changed, even when the sceneRect changes...

Some detail information about my case:
The background image has a dimension of 1920x1080 pixels. I also set a rectangle (0, 0, 1920, 1080) on myQscene->setSceneRect(..), otherwise the view would show all the menu screens at once (like a bird's eye view), rather than just one screen at a time. My application starts in WIndowed mode, but via a keyboard shortcut I can also go into full-screen mode.