How to update only some parts of a painter
-
Hello,
I'm developing a music software, and I have some troubles in the part where a music sheet is displayed and read.
The sheet is designed by a QPainter, which updates itself with a paintEvent each some milliseconds (using a QBasicTimer), depending on the bpm (120 bpm will give a 2 ms update). A cursor goes 1 pixel further each 2 ms in this case. So you'll understand that the painter updates itself very frequently, and I can watch the limits when I draw some Pixmap (for the notes) with the painter : some updates are not considered and so there is a gap between cursor position and the timer (whereas it absolutly must match).Before, I drew points instead of Pixmaps, so I guess the problem comes from them.
My question is : how can I "freeze" some parts of the painter, for example Pixmaps that don't need to be updated every 2 ms ? (unless the player stops the music sheet, everything's erased).
I found the region() function that allow to update only a region, but in my case I especially need to update the cursor (changing its position during each update), and sometimes draw Pixmaps in the painter that will be left until the end of the music.I'm available for further explanation.
Thanks you very much!
-
Hi and welcome to devnet,
Not a direct answer but rather than repainting everything why not have your music sheet completely drawn and just move it as needed ?
-
@SGaist In fact there is a sequence to play in a continuous loop and each loop make a new sheet appear, so the sheet is not frozen all the time
I'm looking for a way to tell Qt "when update(), only update these parts, or don't reload this part until I say so" or something like that, but I didn't manage to find a way in the doc ... -
You could create a QPainter that draws to a QPixmap. You can then update it at any rate you want and any parts of it you want. You would then draw that whole pixmap in a paint event (a single drawPixmap should be pretty fast as it's just a blit).
But give your updates a little more thought. The paintEvent is not gonna happen every 2ms no matter what you do. Typical displays tick at 60Hz which means a paintEvent every ~16ms. You can't go lower than the display's refresh rate. Using the method above you could update parts of the pixmap every 2ms and only do a blit at the display's rate in the paint event with the current state of it.
-
By default Qt clears the background before you draw. You can avoid this by setting the WA_NoSystemBackground or WA_OpaquePaintEvent attribute on the widget but this usually entails ugly artifacts to deal with. Using a QPixmap as a "back buffer" is much cleaner solution.
-
@Chris-Kawa said:
You could create a QPainter that draws to a QPixmap. You can then update it at any rate you want and any parts of it you want. You would then draw that whole pixmap in a paint event (a single drawPixmap should be pretty fast as it's just a blit).
That's a good idea, I'll try it and give you feedback, thanks.
@Chris-Kawa said:
But give your updates a little more thought. The paintEvent is not gonna happen every 2ms no matter what you do. Typical displays tick at 60Hz which means a paintEvent every ~16ms. You can't go lower than the display's refresh rate. Using the method above you could update parts of the pixmap every 2ms and only do a blit at the display's rate in the paint event with the current state of it.
I understand that 2ms is to fast. This speed is due to the cursor that moves 1 pixel further every 2 ms (to follow the play on the sheet), so if I prefer 16ms, that will make the cursor move 8 pixels each 16ms, which is maybe too jolting to see ... But anyway it concerns only the cursor among all objects on the sheet
-
@Peehay said:
so if I prefer 16ms, that will make the cursor move 8 pixels each 16ms, which is maybe too jolting to see ...
It's not a question of preference. It's a hardware constraint. paintEvent won't happen more often that the hardware allows. It's not that you shouldn't update more often. It's physically impossible (unless you've got a high-frequency display, which very few people do).