As i understand, paintEvent()
is executed in 'main loop' of QApplication
object, and can spend time for its internal system tasks, delaying execution of queued slots or other events.
But what if i need to play very smooth animation and i notice periodic main loop delays on that animation? Can i create separate special very stable "main loop" and reassign paintEvent()
calling to it?
P.S. Yes, a GPU, OpenGL and other nice technilogies was invented for smooth game-like animations, i know, i know.
My program: http://www.youtube.com/watch?v=KRk_LNd7EBg
Solution
paintEvent() call frequency stabilization that i am looking for, GPU, OpenGL or hardware vsync will not help me! The issue is a normal behaviour until i calculate pixel's position in integer numbers. There always will be impulses of pixel movement speed. To solve my "problem" i have to measure coordinates in real numbers (double, float) and implement anti-aliasing algorithm.
What you need to do is what you want, but in the opposite way. You propose a special "stable" main loop. What you want to do instead is to do everything but GUI "stuff" in the GUI thread. This will make the main event loop "stable".
The main loop will not be busy doing anything unless it's running the code that you wrote and that you have explicit control over. There's no magic to it at all. If you don't run code in the main loop, it won't be busy. Your comment above is not true in this respect. If you don't run stuff in the main loop, it won't be busy, and everything will happen right away - as soon as an
update()
is called. You might want to actually trace the execution of the code in the debugger to see it for yourself.Qt by itself doesn't bog down the main event loop with unnecessary tasks unless you tell it to do so. What you want is to process everything but GUI interaction in another thread. Stuff like network access, file access, even
QSettings
access -- it should all be done inQObject
s that live in a worker thread. Only the main, GUI thread should handle user interaction, and only in minimal fashion - it should only do what is directly needed to respond to events and to repaint stuff. Any other processing must be done outside of the GUI thread. That's how you get smooth animations.Another important thing is that your animations should be driven by real time, not by assumed time. Thus when you step the animation, you should use
QElapsedTime
to measure how long it was since the last step, and use this time to calculate animated variables. TheQAbstractAnimation
and friends already handle this for you. If you don't use them, you'll need to do it yourself.My hunch is that your code is just bad and does things in non-Qt-idiomatic way, and thus suffers. There are likely simple architectural reasons for why it's not smooth.
Below is a simple example of how you might do it in a
QWidget
. Note the conspicuous absence of anything related to time, except for the FPS calculation. That's the beauty of Qt. ThepaintEvent()
is querying the animation'scurrentValue()
directly. It could also store the value in thenewValue()
slot and use it instead, although that leaves a possibility of delay between the time the value was calculated and the time the value is used - say, due to preemption.I've provided an example that leverages Graphics View Framework in another answer.
In the case of your application, you should be choosing where in the waveform to render the spectrum based on
QElapsedTime
since you've started the playback. That's all there's to it.The example supports Qt 4/5 and leverages
QOpenGLWidget
on Qt 5.4 and later instead of the then-deprecatedQGLWidget
.