Button clicks cause my sizer to act weird

So first off, I have Cody Precord's book now. It looks useful. So
far all I've done with it was that I used it to dispose of a dead
lizard that my cats gave me just as I was opening the box from Amazon
that it came in, but I'm sure I'll find other uses for it, such as
trying to make my non-working scroll bars work.

But the matter at hand is sizers still. Your suggestions on how I was
failing to use sizers correctly were valuable, and I have made great
progress. I now have a window and a panel and some sizers and a
button-adding method that lay out the buttons correctly the first
time, then fails. The first time the window pops up it looks fine.
If I click on a button then window stays the same shape but all the
buttons pile up in the upper-left corner. If I resize the window then
they suddenly appear normal again. If I click a button then window
sizes back to its initial size. If I click another button, then they
all pile up in the upper-left corner again. I've tried Fit(),
Layout(), and Refresh() and none helped.

Sadly, I do not have a simple example for making this fail, only a
complex example, and the snippets below aren't nearly complete enough
to run or test.

The frame is set up with this:
    buttonFrame = wx.Frame( None, title='Button Frame' )
    self.buttonFrame = buttonFrame
    buttonPanel = wx.Panel( buttonFrame, -1 )
    buttonFrame.buttonPanel = buttonPanel
    dirSizer = wx.GridSizer( cols = 3, hgap = 10, vgap = 10 )
    buttonFrame.dirSizer = dirSizer
    cmdSizer = wx.BoxSizer( wx.VERTICAL )
    buttonFrame.cmdSizer = cmdSizer
    panelSizer = wx.BoxSizer( wx.VERTICAL )
    buttonFrame.panelSizer = panelSizer
    panelSizer.Add( dirSizer, 1, wx.EXPAND )
    panelSizer.AddSpacer( 20 )
    panelSizer.Add( cmdSizer, 1, wx.EXPAND )

    buttonPanel.SetSizer( panelSizer )

    frameSizer = wx.BoxSizer()
    buttonFrame.frameSizer = frameSizer
    frameSizer.Add( buttonPanel, 1, wx.EXPAND )
    buttonFrame.SetSizer( frameSizer )
    buttonFrame.SetInitialSize()
    buttonFrame.Show( True )

And the buttons are actually created and destroyed with this:
  def updateButtons( self, interactions ):
    def _findDir( interactions, dir ):
      for i in interactions:
        if ('character:move:%s' % dir) == i.hint():
    return i
      return None
    buttonFrame = self.buttonFrame
    buttonFrame.dirSizer.Clear( True )
    buttonFrame.cmdSizer.Clear( True )

···

##
    ## put the cardinals up first
    ##
    for c in ['', 'Up', '',
              'NW', 'N', 'NE',
        'W','Wait','E',
        'SW','S','SE',
        '', 'Down', '']:
      b = wx.Button( buttonFrame.buttonPanel, label=c )
      i = _findDir( interactions, c )
      if not c or not i:
  b.Enable( False )
      else:
        b.Bind( wx.EVT_BUTTON, self._buttonClick )
  b.interact = i
      buttonFrame.dirSizer.Add( b )

    ##
    ## Now place the other buttons
    ##
    for i in interactions:
      if i.hint() and i.hint().startswith( 'character:move:' ): continue
      b = wx.Button( buttonFrame.buttonPanel, label=i.title() )
      b.Bind( wx.EVT_BUTTON, self._buttonClick )
      b.interact = i
      buttonFrame.cmdSizer.Add( b )
    buttonFrame.SetInitialSize()
    buttonFrame.Fit()
    buttonFrame.Layout()
    buttonFrame.Refresh()

I'm stumped by the fact it lays it out fine if the window is the wrong
size but not if it is the right size. In fact, I can "fix" it just by
putting "buttonFrame.SetSize( (100,100) )" at the start of
updateButtons(). Not really an ideal solution though.

There is a zipfile at: http://infohost.nmt.edu/~schlake/games/x34/x34.zip
The two python files individually are:
http://infohost.nmt.edu/~schlake/games/x34/game.txt
http://infohost.nmt.edu/~schlake/games/x43/wxgui.txt

--
-- Schlake

Hi,

I'm stumped by the fact it lays it out fine if the window is the wrong
size but not if it is the right size. In fact, I can "fix" it just by
putting "buttonFrame.SetSize( (100,100) )" at the start of
updateButtons(). Not really an ideal solution though.

There is a zipfile at: http://infohost.nmt.edu/~schlake/games/x34/x34.zip

the link is invalid, correct one is:
https://infohost.nmt.edu/~schlake/games/x34/x33.zip

The two python files individually are:
http://infohost.nmt.edu/~schlake/games/x34/game.txt
http://infohost.nmt.edu/~schlake/games/x43/wxgui.txt

I had a quick look as I wanted to see what you are doing in "_buttonClick".

In "updateButtons" which is called from "_buttonClick" you clear the sizer and destroy all its windows each time it is called.

Why are you doing this? Couldn't you just change the existing buttons? I.e. enable/disable/hide/show.

You have lots of lines like:

     buttonFrame = wx.Frame( None, title='Button Frame' )
     self.buttonFrame = buttonFrame

Why not:
     self.buttonFrame = wx.Frame( None, title='Button Frame' )

Figuring out problems like this I always resist doing "http://wiki.wxpython.org/MakingSampleApps", but very often when I actually do it I quickly find the problem.

Another very useful tool is the WIT: http://wiki.wxpython.org/Widget%20Inspection%20Tool

Making the following change in "updateButtons" seems to correct the problem.

## buttonFrame.SetInitialSize()
## buttonFrame.Fit()
## buttonFrame.Layout()
## buttonFrame.Refresh()
         buttonFrame.buttonPanel.Fit()
         buttonFrame.buttonPanel.Layout()
         buttonFrame.Fit()

Werner

···

On 06/05/2011 09:28, William D. Colburn (Schlake) wrote:

https://infohost.nmt.edu/~schlake/games/x34/x33.zip

The two python files individually are:
http://infohost.nmt.edu/~schlake/games/x34/game.txt
http://infohost.nmt.edu/~schlake/games/x43/wxgui.txt

Oops, no, the zipfile is wrong! I gave the link to what it should
have been named, but I didn't test it because I didn't think anyone
would trust a zipfile on the internet.

In "updateButtons" which is called from "_buttonClick" you clear the sizer
and destroy all its windows each time it is called.

Why are you doing this? Couldn't you just change the existing buttons?
I.e. enable/disable/hide/show.

Simplicity, basically. Just deleting everything and starting over
from scratch requires less thought and understanding on my part.
Eventually it is probably a good idea, but my interest in this is
everything but the interface. I just want something that works so
that I can stop worrying about it.

You have lots of lines like:

buttonFrame = wx.Frame( None, title='Button Frame' )
self.buttonFrame = buttonFrame

Why not:
self.buttonFrame = wx.Frame( None, title='Button Frame' )

Again, conceptual simplicity. Taking each step explicitly helps me
keep track of where I am.

Figuring out problems like this I always resist doing
"http://wiki.wxpython.org/MakingSampleApps", but very often when I actually
do it I quickly find the problem.

I wrote the sample app first, it was simple, and appeared to work
flawlessly. Then I tried to use it as the model to put it into the
rest of what I had and it stopped working for me.

Another very useful tool is the WIT:
http://wiki.wxpython.org/Widget%20Inspection%20Tool

That one I haven't poked at yet.

Making the following change in "updateButtons" seems to correct the problem.

## buttonFrame.SetInitialSize()
## buttonFrame.Fit()
## buttonFrame.Layout()
## buttonFrame.Refresh()
buttonFrame.buttonPanel.Fit()
buttonFrame.buttonPanel.Layout()
buttonFrame.Fit()

It does fix it! But why? Shouldn't fitting/sizing/layouting the
frame around the panel cascade down through the sizers? It works the
first time.

···

On Fri, May 6, 2011 at 2:35 AM, werner <wbruhin@free.fr> wrote:

--
-- Schlake

...

Figuring out problems like this I always resist doing
"http://wiki.wxpython.org/MakingSampleApps&quot;, but very often when I actually
do it I quickly find the problem.

I wrote the sample app first, it was simple, and appeared to work
flawlessly. Then I tried to use it as the model to put it into the
rest of what I had and it stopped working for me.

At which time it is time again to do another simple sub-set of the larger thing. Either you will figure the problem out by doing that or the likely hood that someone will look at the code to try and figure it out for you. Frankly I nearly didn't look at it as it is more code then is easily understood, at least for me;-) .

Making the following change in "updateButtons" seems to correct the problem.

## buttonFrame.SetInitialSize()
## buttonFrame.Fit()
## buttonFrame.Layout()
## buttonFrame.Refresh()
        buttonFrame.buttonPanel.Fit()
        buttonFrame.buttonPanel.Layout()
        buttonFrame.Fit()

It does fix it! But why? Shouldn't fitting/sizing/layouting the
frame around the panel cascade down through the sizers? It works the
first time.

I think it is because you delete and create again, and the panel's sizer was not told about all these changes, see the doc for wx.Sizer.Layout.

Werner

···

On 06/05/2011 15:04, William D. Colburn (Schlake) wrote:

I haven't looked at the code yet so I'm just guessing that this is the reason, but it fits the symptoms: The sizer layout code has a built-in implicit optimization where if the size of a window does change, or is not needed to change because of changes in size of the items managed by its sizer, then its Layout is not called. In other words, for some window W if W does not receive a EVT_SIZE event, or if W's sizer does not calculate a change in the required size of the layout, then W's Layout is not called. Add this to your recreating everything then you can easily end up with what you are seeing. Most of the time this optimization works well, but once in a while needed changes in the layout are not performed when nested widgets are changed or added. The fix is to simply do an explicit Layout closer in the containment hierarchy to where the changes are actually being made, like in the parent or grandparent.

···

On 5/6/11 6:04 AM, William D. Colburn (Schlake) wrote:

On Fri, May 6, 2011 at 2:35 AM, werner<wbruhin@free.fr> wrote:

Making the following change in "updateButtons" seems to correct the problem.

## buttonFrame.SetInitialSize()
## buttonFrame.Fit()
## buttonFrame.Layout()
## buttonFrame.Refresh()
        buttonFrame.buttonPanel.Fit()
        buttonFrame.buttonPanel.Layout()
        buttonFrame.Fit()

It does fix it! But why? Shouldn't fitting/sizing/layouting the
frame around the panel cascade down through the sizers? It works the
first time.

--
Robin Dunn
Software Craftsman