Fix a bug with layout of grandchildren in wxMSW wxScrolledWindow

Apparently changing the window scrollbars in the middle of a window
deferred repositioning operation is not allowed and confuses
EndDeferWindowPos() which doesn't update the position of _grand_
children correctly in this case.

This bug notably manifested itself when loading a wxScrolledWindow
containing wxStaticBox from XRC, as the parent window was initially
created with the default small size and then relaid out when it was
resized to its real size on first wxEVT_SIZE event which also updated
the scrollbars. As a result, the children of the wxStaticBox were
shifted downwards.

The fix simply flushes the current repositioning operation and starts
one anew in wxWindow::SetScrollbar().
This commit is contained in:
Vadim Zeitlin
2018-06-26 00:58:20 +02:00
parent 0fa00b5159
commit cc931612ee

View File

@@ -1105,6 +1105,39 @@ void wxWindowMSW::SetScrollbar(int orient,
int range,
bool refresh)
{
#if wxUSE_DEFERRED_SIZING
// Work around not documented, but reliably happening, at least under
// Windows 7, but with changing the scrollbars in the middle of a deferred
// positioning operation: the child windows of a window whose position is
// deferred after changing the scrollbar get offset compared to their
// correct position, somehow.
//
// Note that this scenario happens all the time with wxScrolledWindow as
// its HandleOnSize(), which calls AdjustScrollbars() and hence this method
// indirectly, gets called from WM_SIZE handler, which begins deferring
// window positions, and calls Layout() which continues doing it after the
// scrollbar update. So one way of reproducing the bug is to have a window
// with children, such as wxStaticBox, inside a wxScrolledWindow whose size
// gets changed.
//
// Fix this simply by "flushing" the pending windows positions and starting
// a new deferring operation.
if ( m_hDWP )
{
// Do reposition the children already moved.
EndRepositioningChildren();
// And restart another deferred positioning operation as any currently
// existing ChildrenRepositioningGuard objects would be confused if we
// just removed the HDWP from under them.
//
// Unfortunately we have to ignore BeginRepositioningChildren() return
// value here, there is not much that we can do if it fails (but this
// should never happen anyhow).
BeginRepositioningChildren();
}
#endif // wxUSE_DEFERRED_SIZING
// We have to set the variables here to make them valid in events
// triggered by ::SetScrollInfo()
*(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;