Update / repaint a QWidget while it is hidden
-
Hello,
Edit: see my last post (#4) for a detailed description of my problem.
I have a very simple question.
The repaint() and update() method can be called (effectively triggering at some point a paintEvent) when a QWidget is visible, see https://doc.qt.io/qt-5/qwidget.html#repaint and https://doc.qt.io/qt-5/qwidget.html#update .
My question is the following: how can I "repaint" (i.e. trigger a call to paintEvent) while my widget is hidden?
I have a widget I do some processing on while it is hidden, and I would like those modifications to be already there when I call show(). Currently, I have maybe 30 ms where the modifications (text, size, etc.) are processed, and this is unfortunately visible and ugly (inbetween the call to show() and the call to paintEvent).
I can try to provide a minimal example if this is useful.
Thanks a lot!
-
A hidden widget is not painted. If your repaint takes so long I would consider moving the painting to a separate thread on a QImage and then only paint this image in the paint event.
-
Here is a log of the event triggered to be a bit clearer. In my case, I have a QFrame which is the parent of a QTextEdit.
In the order, here is what is happening:
/* I call a update function, and call hide() on the QFrame because I want nothing to be shown during those modifications*/ QFrame: PySide6.QtCore.QEvent.Type.Hide QTextEdit: PySide6.QtCore.QEvent.Type.Hide QFrame: PySide6.QtCore.QEvent.Type.HideToParent /* Some modifications to the content, position and size of the QFrame and QTextEdit, through move, updateGeometry, resize, and e.g. setText */ /* After those modifications, I trigger self.show() on the parent QFrame */ /* Then, AFTER the show(), the event calls are the following: */ QFrame: PySide6.QtCore.QEvent.Type.Move QFrame: PySide6.QtCore.QEvent.Type.Resize QTextEdit: PySide6.QtCore.QEvent.Type.Resize QTextEdit: PySide6.QtCore.QEvent.Type.Show QFrame: PySide6.QtCore.QEvent.Type.Show QFrame: PySide6.QtCore.QEvent.Type.ShowToParent /* The problem is in the following paint call. If my paintEvent for my QTextEdit is slow, then the window will be resized and STILL show the previous text which is unwanted. */ QFrame: PySide6.QtCore.QEvent.Type.Paint QTextEdit: PySide6.QtCore.QEvent.Type.Paint QTextEdit: PySide6.QtCore.QEvent.Type.MetaCall QTextEdit: PySide6.QtCore.QEvent.Type.UpdateLater QFrame: PySide6.QtCore.QEvent.Type.UpdateLater QFrame: PySide6.QtCore.QEvent.Type.UpdateRequest /* For some reason it is only at this call that the new text is printed. */ QFrame: PySide6.QtCore.QEvent.Type.Paint QTextEdit: PySide6.QtCore.QEvent.Type.Paint
What I would like to have, is everything shown when the update is finished, and only then.
Edit:
Thanks a lot for your answer @Christian-Ehrlicher . Do you think this would be doable for text? I need it to be selectable so it is likely that as an image would be difficult, I would guess.
To elaborate a bit, I am building a tool for subtitles, and at subtitle change there is an extremely small flickering (but still visible) when the subtitle changes. Basically, something is messed up with the resize and setting new text, and there is maybe 50 ms during which painting and resizing occurs, which is undesirable. I have tried to identify the issue putting some time.sleep(), and that is how I cam up with the log above.
Edit2: Anyway I am ready to put a bounty on this to anyone who can guide to solve it. Please PM me.
-
Here is a minimal reproducible example: https://pastebin.com/QNxKXQ10
This corresponding video illustrates the result from running the code: https://www.youtube.com/watch?v=pibdxKgbFjw
To explain again:
We have aQFrame
containing aQTextEdit
in its layout.
We call twice the functionrender_subtitles
, first with the textMy first long sub, for example...
, and then a bit later with the textShorter one!
(handled in a thread).This
render_subtitles
is responsible for clearing the old content of theQTextEdit
, putting the new text, resizing and placing at the right place theQFrame
and its childQTextEdit
.I have put a
time.sleep()
in thepaintEvent
from each of theQFrame
andQTextEdit
, to illustrate better my case (otherwise it is like 50 ms only).Basically, in the video, we see that the resizing happens BEFORE the new text appears (and that the old text is still there!). I would like the resizing and the change of text to happen simultaneously, no matter how long
paintEvent
takes. Then, I would like to show those changes. -
This is solved using
self.subtext.repaint()
right after theclear()
for theQTextEdit
, as well as with using a key indicating whether or not the update is finished. We test this key in thepaintEvent
of theQFrame
to effectively paint the new background only when everything is ready.