Details
-
Epic
-
Resolution: Unresolved
-
P2: Important
-
None
-
None
-
None
-
Qt::WA_WState_{Visible,Hidden,ExplicitShowHide}
-
-
4634fbf34 (dev), f57539d4f (6.7), 5ba0982b2 (dev), b393b26c7 (dev), f85c98898 (dev), 0b76a0b32 (6.7), 64f6664f5 (6.7), c8a543e3e (6.7), 1308f7e0b (dev), 2332a9c67 (6.7)
Description
Summary
This is the current understanding. This may change.
Qt::WA_WState_Hidden (as reflected by QWidget::isHidden()) is not just another way to express !Qt::WA_WState_Visible (as refelected by !QWidget::isVisible()). This is explicitly documented by QWidget::isHidden().
The WA_WState_Visible attribute marks whether a widget is currently visible, while the Qt::WA_WState_Hidden attribute determines if the widget should automatically become visible as a result of its parent becoming visible.
Top level widgets, or widgets created as children of already visible windows, will automatically have Qt::WA_WState_Hidden, and will need an explicit show() to be visible.
Calling hide() or setVisible(false) on an existing widget will also add Qt::WA_WState_Hidden,, making sure that the widget doesn't show at a later point without explicit action by the developer.
Calling show() or setVisible(true) on a widget with Qt::WA_WState_Hidden, will remove the attribute, making sure that the widget shows automatically at a later point if needed.
As a result, a widget with Qt::WA_WState_Hidden, can not also be visible, as any showing the widget would have cleared Qt::WA_WState_Hidden,.
The inverse is possible however, as a widget without Qt::WA_WState_Hidden, can be !isVisible() because its parent has not been shown yet, but will be visible once the parent is shown.
Possible combinations
Attributes | Visible | Hidden | ExplicitShowHide | Situation |
---|---|---|---|---|
No attributes | Initial state of child widget of non-visible parent | |||
Only hidden | Initial state of top level widget, or children of visible widgets | |||
Only visible | State after implicitly showing child | |||
Explicitly visible | State after explicitly showing widget | |||
Visible and hidden | Not possible/valid | |||
Explicitly hidden | State after explicitly hiding widget | |||
Only explicit | Can happen. Unclear semantics | |||
All attributes | Not possible/valid |
No attributes
This state can happen when:
- Creating a child widget of a non-visible parent
The process is as follows:
- The hidden attribute is initially set by QWidgetPrivate::init
- As the widget is a child we end call setParent, which recurses into setParent_sys
- Which removes the hidden attribute
- And doesn't apply it again due to the widget having a non-visible parent
Only hidden
This state can happen when:
- Creating a top level widget
- Creating a child widget of an already visible parent
The process is as follows:
- The hidden attribute is initially set by QWidgetPrivate::init
- If the widget is a top level, no further parenting is needed. If it's a child:
- We end call setParent, which recurses into setParent_sys
- Which first removes the hidden attribute
- Then reapplies it, after checking if the child's parent is visible
- Then we do a seemingly redundant check for a visible parent in setParent, and reapply the hidden attribute again
- We end call setParent, which recurses into setParent_sys
We also have some places where we clear WState_ExplicitShowHide, putting us in this situation:
- QSizeGrip::eventFilter for QEvent::WindowStateChange
- After calling first calling QWidget::setVisible, so done to not overwrite WState_ExplicitShowHide
- Should be replaced by call to QWidgetPrivate::setVisible
- After calling first calling QWidget::setVisible, so done to not overwrite WState_ExplicitShowHide
- QStatusBar::hideOrShow()
- After calling hide(), so done to not overwrite WState_ExplicitShowHide
- Should be replaced by call to QWidgetPrivate::setVisible
- After calling hide(), so done to not overwrite WState_ExplicitShowHide
Only visible
This state can happen when:
- A child widget is shown implicitly by Qt
The process is as follows:
- Showing/setVisible(true) any widget will end up in QWidgetPrivate::setVisible, where we unset WS_Hidden
- We then mark the widget as visible in QWidgetPrivate::show_helper()
- Children are then showed via QWidgetPrivate::showChildren
- Which ends up calling QWidget::setVisible(true)
- Which sets WA_WState_ExplicitShowHide and calls QWidgetPrivate::setVisible
- Which ends up calling QWidget::setVisible(true)
1 The fact that we call QWidget::setVisible and not QWidgetPrivate::setVisible means we currently apply ExplicitShowHide even to children we're showing ourselves, which seems like a bug. Fixed by https://codereview.qt-project.org/c/qt/qtbase/+/536262
We also have some places where we clear WState_ExplicitShowHide, putting us in this situation:
- QStatusBarPrivate::tryToShowSizeGrip
- Before and after triggering _q_showIfNotHidden for the internal size grip
Explicitly visible
This state can happen when:
- A widget is shown "explicitly"
- The definition of "explicit" is not well defined. Right now it includes
- Calling QWidget::setVisible(true)
- Possibly via QWidget::show()
- Calling QWidget::setVisible(true)
- The definition of "explicit" is not well defined. Right now it includes
The process is as follows:
- Something is calling calling QWidget::setVisible(true)
- Which sets WA_WState_ExplicitShowHide
- Then calls QWidgetPrivate::setVisible
- Where we unset WS_Hidden
- And then mark the widget as visible via QWidgetPrivate::show_helper()
Visible and hidden
This state is not possible in practice, unless set explicitly via setAttribute.
- Showing
- QWidgetPrivate::setVisible will unconditionally unset WS_Hidden
- QWidgetPrivate::show_helper() will unconditionally set WS_Visible
- Hiding
- QWidgetPrivate::setVisible will unconditionally set it WS_Hidden
- QWidgetPrivate::hide_helper() will unconditionally unset WS_Visible
The QWidget::isHidden() documentation explicitly says that this can not happen.
We should perhaps consider asserting somewhere that we don't end up in this situation.
Explicitly hidden
This state can happen when:
- A widget is hidden "explicitly"
- The definition of "explicit" is not well defined. Right now it includes
- Calling QWidget::setVisible(false)
- Possibly via QWidget::hide()
- Possibly via QWidget::close() for child widgets, in QWidgetPrivate::handleClose
- Possibly via QWidget::hide()
- Calling QWidget::setVisible(false)
- The definition of "explicit" is not well defined. Right now it includes
The process is as follows:
- We end up in QWidget::setVisible(false)
- Which sets WA_WState_ExplicitShowHide
- Then calls QWidgetPrivate::setVisible
- Which will unconditionally set it WS_Hidden
- And call QWidgetPrivate::hide_helper() which will unconditionally unset WS_Visible
Only explicit
Under normal circumstances this should not happen.
- We set WState_ExplicitShowHide from QWidget::setVisible()
- Which in turn ends up with either WA_WState_Visible or WA_WState_Hidden set.
- We set WState_ExplicitShowHide from QWidgetPrivate::setParent_sys()
- We do so to restore the "explicitly hidden" state (Hidden+ExplicitShowHide) to what it was before we tweaked Visible/Hidden as part of the reparenting
- We first unset both Visible and Hidden
- Then apply Hidden if the widget is now a top level, or a has a visible parent, or was explicitly hidden
- Then apply ExplicitShowHide if the widget was explicitly hidden
- So the only way we can end up setting ExplicitShowHide is if the widget was already also Hidden, in which case the widget will also have Hidden when we're done with setParent_sys().
- We do so to restore the "explicitly hidden" state (Hidden+ExplicitShowHide) to what it was before we tweaked Visible/Hidden as part of the reparenting
- We set WState_ExplicitShowHide in the QRubberBand constructor
- But follow it up with setVisible(false)
- Making the final state "explicitly hidden"
- We can remove the call to set WState_ExplicitShowHide, as QWidget::setVisible() will do that
Some corner cases that end up here are:
Due to propagating WState_ExplicitShowHide to children on setVisible (likely a bug), we end up with children having WState_ExplicitShowHide after the parent is hiddenWe set WState_ExplicitShowHide from QWidgetWindowPrivate::setVisible()Triggered via QWindow::setVisible()We do so to restore the ExplicitShowHide state after calling QWidgetPrivate::setVisible()Which we know will end up with either Visible or Hidden
But we then also restore WState_HiddenWhich means that if the original widget was explicitly visible, and then made invisible, we'll end up removing Visible via QWidgetPrivate::setVisible(), and then also removing Hidden, while keeping ExplicitShowHide.
- Fixed in https://codereview.qt-project.org/c/qt/qtbase/+/539505
- QAlphaWidget::run() and QRollEffect::run() set ExplicitShowHide and removes Hidden, saying "it is roughly equivalent to calling setVisible(true) without actually showing the widget".
All attributes
The same reasoning as for "Visible and hidden" should apply here. If a widget can't have both WState_Visible and WS_Hidden at the same time, it can't have those plus another attribute.
2 If we end up QWidgetWindowPrivate::setVisible(true) for a already explicitly hidden widget, we'll end up setting WState_Visible via QWidgetPrivate::setVisible(), but then restore WState_Hidden and WState_ExplicitShowHide. This is a bug. Fixed in https://codereview.qt-project.org/c/qt/qtbase/+/539505
During QWidget::destroy() we set WA_WState_Created to false, and then delete the QWidgetWindow. As a result we skip calling hide_helper() from QWidgetPrivate::setVisible(false), where we normally unset WA_WState_Visible, and the widget ends up isVisible() even after being destroyed. This is a bug. Fixed in https://codereview.qt-project.org/c/qt/qtbase/+/539506/2
History
Qt::WA_WState_ExplicitShowHide
Introduced as CreateHidden
commit fafd940011ba126eefd3f4d30c2492a5f9dcfacd Date: Tue Jul 30 16:05:15 2002 +0100 1. Added the possibility to hide menu and menubar items similar to widgets 2. Make use of this feature in QAction 3. Added a tricky way (via WState_CreatedHidden) to distinguish explicit user hide()s from implicit hides. This allows us to implement menu item semantics with toolbar widgets: new QToolButton( toolBar ); => always shows the button through ChildEvent insert (new QToolButton( toolBar ))->hide(); => does *not* show the button [ new! ] New functions: QMenuData::setItemVisible(bool), implemented for both menu bar and popup menu. QAction::setVisible(bool) ( QActionGroup::setVisible(bool) )
Renamed in a721e2dd3bb2d5a953a09f8adfb47a95b548b2bb
- WState_ForceHide ➡ WState_Hidden
- WState_CreatedHidden ➡ WState_ExplicitShowHide
Unanswered questions
What are the practical implications of the three different non-visible states?
Attributes | Visible | Hidden | ExplicitShowHide | Situation |
---|---|---|---|---|
No attributes | Not visible, but also not hidden | |||
Only hidden | Hidden, but not explicitly | |||
Explicitly hidden | Explicitly hidden |
We treat these states differently inside Qt, but exactly how needs some more diggging.
What does it mean to be "explicitly" shown/hidden?
What kind of actions will/should result in this state?
- QWidget
- setVisible ( today, also for children)
- show ( today, also for children)
- hide ( today, also for children as a result of the show)
- close ( today)
- QWindow
- setVisible
- show
- hide
- close
- User action
- Clicking the close button of a window
- Minimizing a window
- System actions
- System shutdown, closing all apps and their windows
The answer to these questions are likely informed by the answers to what the practical implication of being "explicit" is.
Should ExplicitShowHide persist
- Is the action of explicitly showing a widget something that should persist into the widget being "explicitly hidden" once hidden? And vice versa?
- Should Qt ever reset/clear this attribute when it internally does show/hide that would not normally have added this attribute, or should it make sure the attribute state is kept as is?
- Should the attribute persist when saving and restoring the widget state to/from disk?
Attachments
Issue Links
- resulted in
-
QTBUG-127806 QLineEdit selects all text when receiving focus.
- Closed