Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-114047

QWidget reactivates parent layout when showing widgets but not when hiding them, which causes flicker and window resizing

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 6.4.3
    • Widgets: Layout
    • None
    • macOS 10.14
    • All

    Description

      When calling QWidget::setVisible(true) with a visible parent with layout, parent->d_func->layout->activate() is called synchronously, which causes the layout to be recalculated and space for the new widget is added.

      When calling QWidget::setVisible(false) with a visible parent with layout, only q->parentWidget()>d_func()>layout->invalidate() is called, and a QEvent::LayoutRequest event is posted to activate the layout “later”.

      Therefore, when a child “A” is shown and then a child “B” is hidden, an intermediate bogus layout state is created where the space for child A has been added but space for child B has not been removed. This can cause some bad things:

      1. A frame of garbage rendering where child A is rendered and child B is not rendered but the space for child B still exists in the layout where it used to be;
      2. The window grows permanently larger if the bogus layout size is larger than the current window size and it can grow.

      Calling QCoreApplication::sendPostedEvents(nullptr, QEvent::LayoutRequest) after all children are shown/hidden does work to force layouts to be updated to their correct state as a workaround, but this seems to me like (a) a shotgun approach and (b) seems to be undocumented except in one comment in a very old bug report.

      (If one happens to know exactly which layouts will be affected it seems like it is also possible to call QLayout::setEnabled before and after the layout changes on those layouts but this is also not really a workable solution.)

      Looking to see if this bug was already reported there seem to be very old reports in QTBUG-10277 and QTBUG-15832 which were closed “by design”, but it seems to me at the least when it’s time to paint that a widget’s layout really should be up-to-date?

      The attached test case demonstrates the issue, and I have also attached a screen recording that shows the one frame of flicker and the window size changing needlessly. (In a real app the issue is more pronounced because there more content being shown/hidden.)

      I do not think this is necessarily OS-specific but I do not have time to check in another environment at the moment. With the attached reduced test case it does seem like there is a race and sometimes the LayoutRequest is sequenced before the next paint and so the window resizes but there is no flicker of content, but it is quite reliable for me in a production app.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            csnover C S
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes