Correct way to force a complete sizer layout

35 views
Skip to first unread message

Les Newell

unread,
Jan 28, 2021, 8:49:37 AM1/28/21
to wx-users
What is the correct way to force a window and all of it's children to
layout as if the window has just been created?

I have a window that changes the number and size of controls depending
on user input. I want to force a complete sizer layout to take into
account the new layout. Simply calling GetSizer()->Layout() does not
work. I resorted to recursing through all windows and sizers, calling
Layout() on each sizer and InvalidateBestSize() on each window. This
mostly works but in some cases I still end up with the wrong window size.

Vadim Zeitlin

unread,
Jan 28, 2021, 11:41:36 AM1/28/21
to wx-u...@googlegroups.com
On Thu, 28 Jan 2021 13:49:34 +0000 Les Newell wrote:

LN> What is the correct way to force a window and all of it's children to
LN> layout as if the window has just been created?

Call wxWindow::Layout() on the top-most window whose layout you want to
change (usually just the top level window, i.e. the parent frame, but it
could be also some panel inside it if you want to limit the re-layout to
this panel only).

LN> I have a window that changes the number and size of controls depending
LN> on user input. I want to force a complete sizer layout to take into
LN> account the new layout. Simply calling GetSizer()->Layout() does not
LN> work.

It's a bit confusing, but wxSizer::Layout() is not quite the same as
wxWindow::Layout(), the latter also updates the size available to the sizer
which is very important if the size of the window has actually changed. If
it didn't change, however, calling Layout() on the window itself and
GetSizer()->Layout() should be equivalent.

LN> I resorted to recursing through all windows and sizers, calling
LN> Layout() on each sizer and InvalidateBestSize() on each window. This
LN> mostly works but in some cases I still end up with the wrong window size.

You definitely don't need to manually recurse through anything, Layout()
already does it (either one). It looks like there could be some other
problem, e.g. maybe you don't delete the old controls before updating the
layout or something like this?

In any case, calling wxWindow::Layout() should always work and if you find
a reproducible case in which it doesn't, please report it as a bug.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Les Newell

unread,
Jan 28, 2021, 12:35:55 PM1/28/21
to wx-u...@googlegroups.com
Thanks Vadim,

Layout() followed by Fit() mostly works but I get redraw problems if I
have a wxStdDialogButtonSizer. The controls are repositioned in the
wxStdDialogButtonSizer but the background isn't cleared so you see what
looks like overlapping buttons if the window width changes. Calling
Refresh() fixes it. This is on MSW, master as of about April 2020.

I still have one window that is misbehaving when I enable/disable a
panel. I'll do some more testing to see if I'm doing anything stupid.

Les

Vadim Zeitlin

unread,
Jan 28, 2021, 3:39:03 PM1/28/21
to wx-u...@googlegroups.com
On Thu, 28 Jan 2021 17:35:53 +0000 Les Newell wrote:

LN> Layout() followed by Fit() mostly works

I'm not sure why would you use Fit() _after_ Layout(). Fit() just sets the
window size to the best size it would like to have, and there are two
possibilities here:

1. Either the current size is different from the best size and in this case
Fit() will change it and call Layout() as a side effect anyhow.
2. Or the current size is already the same as the best size, in which case
Fit() simply does nothing and, in particular, you still have to call
Layout() if you really need to re-layout the children.

So, if anything, I might see how calling Fit() first and then Layout()
could be useful, but I can't imagine any situation in which calling them in
the opposite order would make sense.

LN> but I get redraw problems if I have a wxStdDialogButtonSizer. The
LN> controls are repositioned in the wxStdDialogButtonSizer but the
LN> background isn't cleared so you see what looks like overlapping buttons
LN> if the window width changes. Calling Refresh() fixes it. This is on
LN> MSW, master as of about April 2020.

This might be a bug, but I'd really need to have some way of reproducing
it to say more.

Les Newell

unread,
Feb 25, 2021, 10:21:24 AM2/25/21
to wx-u...@googlegroups.com
For future reference I found why I was struggling to get layouts to work
correctly. I use the wxSmith Code::Blocks plugin to lay out my windows
and it has a tendency to call to wxSizer::SetSizeHints() for pretty much
every sizer. That really messes with wxWindow::Layout() if you hide
controls. I was getting all sorts of completely unpredictable results
until I manually commented out all of these calls. I now only call
SetSizeHints once for the parent window after modifying a layout.
Of course next time I edit a window layout the plugin will stick them
back in...

Les
Reply all
Reply to author
Forward
0 new messages