PDA

View Full Version : Ugly move with a top-level setMasked widget



nooky59
17th December 2007, 11:12
Hi,

I've searching a lot in the forum but I don't think I've found something interesting regarding it.

I have made a simple top-level wndow with a custom shape using a QLabel, a QPixmap and the so famous setPixmap et SetMask(pixmap.mask()).

I've too, as in the shaped clock example, implemented the mouseMoveEvent and mousePressEvent in order to move the window.

It seems to really sucks if I move the window over some other apps (for example Visual Studio or Firefox). A picture is better than words (as it's hard to explain for a non native english people ;o)) so look at the attached image.

This effect is drastically intensified if I move the mouse fast but even if I try to move slowly, this problem appears really soon...

However, if I move it on the Windows desktop, it move smoothly !

I wonder if it's related to Qt as I've tried a fancy WinAMP skin and this problem were here too but a lot lesser visible.

Is there a way I can solve it ?

Curiously, with a star example I've found on this forum, there is no problem even if the source code is the same ! Could it be due to the size of the image or if the source PNG is not smoothly anti-aliased on the edge of the shape ?

wysota
17th December 2007, 12:00
Size surely matters and probably so does the complexity of the mask. Try using a different image and see if the problem persists.

nooky59
17th December 2007, 13:47
I've tried with another picture, one from the official PNG page :

http://www.libpng.org/pub/png/img_png/OwlAlpha-0.5.png

In this size, there is the same problem, if I reduce it to 320x240 with The Gimp and launch the program again, it is perfect.

So, yes, it's really related to the image size.

Does someone see a way to have a perfect move ? In this simple case, my widget is a QLabel with setPixmap and setMask and I don't override paint event, but I think I have another code snippet I've written with a paint event, double buffering... but it seems to be problematic as well.

nooky59
17th December 2007, 14:02
Wonderful, it seems I've found a trick that could help but advice of an expert would be useful !

I've tried, just to make an effect, to call setWindowOpacity(0.1) during the move of the QLabel with the mask and now this is a very fluent move !!!

As it was a little too transparent, I've played with the opacity ratio but it's fun to see if I set it to 0.99, it's near full opaque but now it rocks !!! Very funny.

I don't know why, I suppose there are some routines in the heart of Qt to handle transparent widget but it kicks some ass !

But I must admit that setting the opacity to a lower ratio (so rendering the widget transparent during the move) is quite pretty.

EricF
17th December 2007, 14:09
Is there a reason why you make your widget a QLabel. Why not use a plain QWidget and reimplement the paint event to display your image ?

nooky59
17th December 2007, 14:16
Hmmm only for the simplicity of the example and to let Qt handle its paint event.

I've tried both approach but in order to solve the jerked move problem, I would really verify that it was not my paint event, resize event, ... that caused the problem.

There is the problem in both cases but sure creating my own QWidget is far better and I will perhaps gain more perfs if I use double-buffering on an off-screen pixmap before painting.

But setting the window opacity give good results. It's not perfect but I think it's quite comparable to winamp now so if users like a fancy skinned app, they must deal with the little artifacts remaining ;o)

wysota
17th December 2007, 14:42
Qt4 widgets are all double buffered by default.

nooky59
17th December 2007, 15:15
Yes, I know but in the Qt 4 with C++ book even if they said that double-buffering is handled by Qt, they showed a useful example about how to do it so it seems that it can be useful to do it yourself sometimes.

Hmm, I'm sad, setting the opacity product a different problem rendering but it's not perfect at all. It's very strange, if I move the top-level masked widget on the windows desktop, it's perfect even if I move fastly.

I really don't know if there is something to do. With WinAMP, it's the same problem. I don't know which technology they use to program it but I don't think this is Qt. So the problem is the same, with small fancy skin, WinAMP move smoothly on others apps but as soon as the skin is tricky and big, the problem is the same.

I think it's too related to the computer (even if I'm running a NVidia GeForce FX 5200 here) cause I think the problem is present but lesser on my laptop.

wysota
17th December 2007, 15:30
Yes, I know but in the Qt 4 with C++ book even if they said that double-buffering is handled by Qt, they showed a useful example about how to do it so it seems that it can be useful to do it yourself sometimes.

Maybe they meant caching and not double buffering?

EricF
17th December 2007, 15:48
Maybe they meant caching and not double buffering?

Yeah I think your right if I have the same book than original poster. They keep the background in a pixmap and when rendering, they render the background pixmap and then draw dynamic content over it.

nooky59
17th December 2007, 15:59
Hmm, they said precisely that :


In Qt 4, QWidget handles this automatically, so we rarely need to worry about widgets flickering. Still, explicit double buffering remains beneficial if the widget's rendering is complex and needed repeatedly. We can then store a pixmap permanently with the widget, always ready for the next paint event, and copy the pixmap to the widget whenever we receive a paint event. It is especially helpful when we want to do small modifications, such as drawing a rubber band, without recomputing the whole widget's rendering over and over.

Anyway, such a trick couldn't solve the problem. I've made another test with a QWidget instead of a QLabel, overriding the paintEvent to draw the pixmap and doing the setMask once in the resize event.

Then, I've put a conditionnal breakpoint on the paintEvent (it breaks only after the app spend 10 times in the paintEvent) and if I move a lot the app, the problem is the same as in the attachment of the first post and the paintEvent is not called.

So there is really nothing to do, the behaviour of the move will depend of the size, the complexity of the skin, and even the computer on which the app will be executed...

I think users will be compassionated about that if some flag-ships apps as WinAMP do the same...

wysota
17th December 2007, 16:26
Hmm, they said precisely that
They meant caching - "store" and "repeatedly" suggest that.


I think users will be compassionated about that if some flag-ships apps as WinAMP do the same...

Try on some completely different computer - owned by someone else and with different hardware as you might be experiencing some system issue (drivers? OS?).