PDA

View Full Version : Calling update() from paintEvent()



wonder.mice
11th January 2008, 10:22
Hello,

Calling update() from paintEvent() handler results in interesting behavior under MS Windows (in Mac OS X and Linux everything is ok). For example, I want to make simple animation, like in demos/composition/. For doing animation I will call update() function in the end of paintEvent() handler to force next repaint. In paintEvent() i will use current time to sync animation. This way demos/composition/ works, as I understand.

It works very good, but when I'm pushing left mouse button down on window caption, animation stops. Animation resumes if I began to drag window. The same situation is with resize. When I release mouse button everything is ok again.

Calling update() from paintEvent() is just an example. Actually I need to emit some signals from other thread (using QueuedConnection) to GUI thread. But those signals doesn't reach slots when left mouse is down on window caption. But they all will reach slots when I release mouse button. Problem looks the same for me, but the first one is easy to reproduce.

Anyone know what is going on?

To reproduce bug you can take examples/widgets/analogclock/. Comment line

timer->start(1000); in the constructor (AnalogClock::AnalogClock(QWidget *parent))
in analogclock.cpp. In void AnalogClock::paintEvent(QPaintEvent *) call update() in the end of this function. And the last, make time variable in paintEvent() static, like this:


static QTime time(1, 1, 1);
time = time.addSecs(30);

Thats all.

actually I don't need any animation. This case is just an example of how to reproduce the situation. I want to know why Qt signal-slot mechanism acts this way when I am pressing left mouse button on window caption. What I really need is to be able to send signals from some thread to GUI thread (yes, via Queued Connection) and to be sure that slots will be called while I am holding this left mouse button down. Now slots will be called for all signals when I will release the mouse button.

wysota
11th January 2008, 11:59
Why would you call update() from a paintEvent()? It's an obvious misdesign... If you want to make an animation, use a timer or a timerEvent. Triggering a repaint from another repaint is stupid because all you application does is to repaint itself, probably rising CPU usage sky high.

wonder.mice
11th January 2008, 12:31
Calling update() from paintEvent() is just an example. Actually I need to emit some signals from other thread (using QueuedConnection) to GUI thread. But those signals doesn't reach slots when left mouse is down on window caption. But they all will reach slots when I release mouse button. Problem looks the same for me, but the first one is easy to reproduce.
I don't need it. I don't need any animation at all. This is just an example of what works perfect on Mac and Linux and works bad on Windows. If you want another testcase - run some thread and try to emit signals from it to gui thread using Queued Connection. Slots will be called only when you release the left mouse button.

wysota
11th January 2008, 13:51
This is just an example of what works perfect on Mac and Linux and works bad on Windows.
Well, yes. Microwave ovens are not the best sun bath machines either. But hey, they were never meant to be!

If you do with some Qt component something it wasn't designed for, you do it on your own responsibility. We can only say "you shouldn't do that, it won't work". If you choose to proceed, you do it at your own risk.

As for your other doubt - if the application doesn't have the CPU, it won't process events. If you click on the window decoration which is not a part of the application but rather the windowing system, you might take away CPU from the application and it can't do anything about it. Conclusions are yours to draw.

wonder.mice
11th January 2008, 13:51
You can look on examples\threads\mandelbrot\ to see the effect. On Windows it doesn't updates its content while resizing but on Mac/Linux it does.

wonder.mice
11th January 2008, 14:02
As for your other doubt - if the application doesn't have the CPU, it won't process events. If you click on the window decoration which is not a part of the application but rather the windowing system, you might take away CPU from the application and it can't do anything about it. Conclusions are yours to draw.

It's nonsense. So you want to say, that when I click on window decoration in Windows everything stopped? =)))) You can take a look on Windows native applications like Clock or Media Player for example - they work even if you click on their caption. More over, slots connected to timer still works in this case. It is very bad design if GUI is dead while user holding mouse button on caption or looking on system menu opened with Alt+Space.

And if you want calling update() from paintEvent() is implemented in Qt composition demo, so this way is not that bad. BTW.

wysota
11th January 2008, 14:20
It's nonsense. So you want to say, that when I click on window decoration in Windows everything stopped? =))))
I didn't say that. I only said that if you take the CPU from the application, it won't process events. If those applications you mention do something to prevent it or if Qt application do something that causes it, you might end up observing the effect you have seen.


More over, slots connected to timer still works in this case.
Because timer don't grab the mouse while windows and window managers might. Qt acts in this way that if you click on something, it grabs the mouse. Maybe if you click on a decoration, the window manager grabs the mouse preventing mouse events from reaching the application. Maybe your window manager doesn't schedule repaint events to the application while the window is being moved. Either way the application can't process events - it might be that there is nothing to process at all.


It is very bad design if GUI is dead while user holding mouse button on caption or looking on system menu opened with Alt+Space.
Yes, I can agree with that.


And if you want calling update() from paintEvent() is implemented in Qt composition demo, so this way is not that bad. BTW.
If it is and is not some special case, then it is bad. I can always obscure the window by moving some other window over it and in such a case I don't want my widget to repaint twice (or constantly like in your example).

BTW. I'm currently looking at the composition example and I don't see a paintEvent reimplemented anywhere and the only call to update() is in setCirclePos() which is fine - the position has changed and so the widget needs to be repainted.

wonder.mice
11th January 2008, 14:31
BTW. I'm currently looking at the composition example and I don't see a paintEvent reimplemented anywhere and the only call to update() is in setCirclePos() which is fine - the position has changed and so the widget needs to be repainted.

Look at the end of CompositionRenderer::paint() method which is called from paintEvent() (from demos mini-framework that used by many Qt demos)

wonder.mice
11th January 2008, 14:41
I think you don't understand me.

I need to have way to emit signals from some thread (for example downloads xxx pics from server and wants to notify GUI about how many pics it has downloaded) and to have slots "in GUI thread" that will be called in GUI thread context as handlers of those signals. This works, but on windows when I click on caption or on resize corner GUI stops to receive events (with emitted signals) from other thread, but it can still handle timer events and even paint events if update() was called as slot for timer signal (update() slot connected to some timer). So I can't understand this - when I call update from paintEvent() it not works when mouse is down on caption but when update() called from timer - everything is ok.

BTW in Qt 4.1.4 we found this problem on Mac too, so it was fixed some where between 4.1.4 and 4.3.2 for Mac platform.