Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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!


  • Lifetime Qt Champion

    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 a QFrame containing a QTextEdit in its layout.
    We call twice the function render_subtitles, first with the text My first long sub, for example..., and then a bit later with the text Shorter one! (handled in a thread).

    This render_subtitles is responsible for clearing the old content of the QTextEdit, putting the new text, resizing and placing at the right place the QFrame and its child QTextEdit.

    I have put a time.sleep() in the paintEvent from each of the QFrame and QTextEdit, 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 the clear() for the QTextEdit, as well as with using a key indicating whether or not the update is finished. We test this key in the paintEvent of the QFrame to effectively paint the new background only when everything is ready.


Log in to reply