Sizing Widgets in Sizers, and Sizing Frames based on the size of their content.

I have a wx.SpinCtrl that I created and added to a horizontal BoxSizer

class Controls(wx.Panel):
def init(self, parent):
wx.Panel.init(self, parent)
self.parent = parent
self.GoButton = wx.Button(self, ID_GO_BUTTON, ‘Go’)
self.ResetButton = wx.Button(self, ID_RESET_BUTTON, ‘Reset’)
self.SingleStepButton = wx.Button(self, ID_SINGLESTEP_BUTTON, ‘Step’)
self.DensityCtrl = wx.SpinCtrl(self, ID_DENSITY_SPINNER)
self.DensityCtrl.SetValue(10)
print dir(self.DensityCtrl)

    hbox = wx.BoxSizer(wx.HORIZONTAL)
    hbox.Add(self.GoButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.ResetButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.SingleStepButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.DensityCtrl, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    self.SetSizer(hbox)           

The DensityCtrl is too wide. and I’m not sure how to narrow it and still have the Sizer work as expected.

In addition, my Frame contains two Panels in a VERTICAL BoxSizer. The one above which goes along the bottom, and one I draw on that fills the vast majority of the Frame. The panel that gets drawn on is a specific size, and often I find myself drawing below the top edge of my controls Panel. How can I resize the Frame based on the size of the two panels?

···


Stand Fast,
tjg.

I have a wx.SpinCtrl that I created and added to a horizontal BoxSizer

class Controls(wx.Panel):

def __init__(self, parent):
    wx.Panel.__init__(self, parent)


    self.parent = parent
    self.GoButton = wx.Button(self, ID_GO_BUTTON, 'Go')


    self.ResetButton = wx.Button(self, ID_RESET_BUTTON, 'Reset') 
    self.SingleStepButton = wx.Button(self, ID_SINGLESTEP_BUTTON, 'Step')


    self.DensityCtrl = wx.SpinCtrl(self, ID_DENSITY_SPINNER)
    self.DensityCtrl.SetValue(10)


    print dir(self.DensityCtrl)

    hbox = wx.BoxSizer(wx.HORIZONTAL)


    hbox.Add(self.GoButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.ResetButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)


    hbox.Add(self.SingleStepButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.DensityCtrl, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)


    self.SetSizer(hbox)           

The DensityCtrl is too wide. and I’m not sure how to narrow it and still have the Sizer work as expected.

try changing it to:
hbox.Add(self.DensityCtrl, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)

In addition, my Frame contains two Panels in a VERTICAL BoxSizer. The one above which goes along the bottom, and one I draw on that fills the vast majority of the Frame. The panel that gets drawn on is a specific size, and often I find myself drawing below the top edge of my controls Panel. How can I resize the Frame based on the size of the two panels?

self.Fit() ?

···

On Wed, Apr 9, 2008 at 6:02 PM, Timothy Grant timothy.grant@gmail.com wrote:

Been working on that small runnable example, but it’s cutting down a fairly large chunk of code. Small = Easy. Small AND Runnable = more difficult.

···

On Wed, Apr 9, 2008 at 5:03 PM, C M cmpython@gmail.com wrote:

On Wed, Apr 9, 2008 at 6:21 PM, Timothy Grant timothy.grant@gmail.com wrote:

On Wed, Apr 9, 2008 at 3:11 PM, C M cmpython@gmail.com wrote:

On Wed, Apr 9, 2008 at 6:02 PM, Timothy Grant timothy.grant@gmail.com wrote:

I have a wx.SpinCtrl that I created and added to a horizontal BoxSizer

class Controls(wx.Panel):

def __init__(self, parent):
    wx.Panel.__init__(self, parent)





    self.parent = parent
    self.GoButton = wx.Button(self, ID_GO_BUTTON, 'Go')





    self.ResetButton = wx.Button(self, ID_RESET_BUTTON, 'Reset') 
    self.SingleStepButton = wx.Button(self, ID_SINGLESTEP_BUTTON, 'Step')





    self.DensityCtrl = wx.SpinCtrl(self, ID_DENSITY_SPINNER)
    self.DensityCtrl.SetValue(10)





    print dir(self.DensityCtrl)

    hbox = wx.BoxSizer(wx.HORIZONTAL)





    hbox.Add(self.GoButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.ResetButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)





    hbox.Add(self.SingleStepButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.DensityCtrl, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)





    self.SetSizer(hbox)           

The DensityCtrl is too wide. and I’m not sure how to narrow it and still have the Sizer work as expected.

try changing it to:
hbox.Add(self.DensityCtrl, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)

In addition, my Frame contains two Panels in a VERTICAL BoxSizer. The one above which goes along the bottom, and one I draw on that fills the vast majority of the Frame. The panel that gets drawn on is a specific size, and often I find myself drawing below the top edge of my controls Panel. How can I resize the Frame based on the size of the two panels?

self.Fit() ?

Thank you! The first suggestion was perfect and much improves things.

Great–the “0” indicates make it a non-stretchable control, that’s the key.

The second one definitely changed the way things work, though it didn’t work the way I expected. I’m sure it’s a bug in my code somewhere. Digging now!

If you could post a small runnable sample, it’d be clearer to see what the problem might be. I probably should have asked for that instead of just mentioning .Fit().


Stand Fast,

tjg.

Well small and runnable ended up out of my reach. I’m attaching the code for my little version of Conway’s game of life (something that has fascinated me since before I knew what programming was). It works pretty well, but I hate the way it resizes itself so any tips there would be greatly appreciated.

Also any other tips or nuances or just plain “your code sucks because…” comments are welcome.

life.py (12.7 KB)

···

On Wed, Apr 9, 2008 at 5:22 PM, Timothy Grant timothy.grant@gmail.com wrote:

On Wed, Apr 9, 2008 at 5:03 PM, C M cmpython@gmail.com wrote:

On Wed, Apr 9, 2008 at 6:21 PM, Timothy Grant timothy.grant@gmail.com wrote:

On Wed, Apr 9, 2008 at 3:11 PM, C M cmpython@gmail.com wrote:

On Wed, Apr 9, 2008 at 6:02 PM, Timothy Grant timothy.grant@gmail.com wrote:

I have a wx.SpinCtrl that I created and added to a horizontal BoxSizer

class Controls(wx.Panel):

def __init__(self, parent):
    wx.Panel.__init__(self, parent)






    self.parent = parent
    self.GoButton = wx.Button(self, ID_GO_BUTTON, 'Go')






    self.ResetButton = wx.Button(self, ID_RESET_BUTTON, 'Reset') 
    self.SingleStepButton = wx.Button(self, ID_SINGLESTEP_BUTTON, 'Step')






    self.DensityCtrl = wx.SpinCtrl(self, ID_DENSITY_SPINNER)
    self.DensityCtrl.SetValue(10)






    print dir(self.DensityCtrl)

    hbox = wx.BoxSizer(wx.HORIZONTAL)






    hbox.Add(self.GoButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.ResetButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)






    hbox.Add(self.SingleStepButton, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
    hbox.Add(self.DensityCtrl, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)






    self.SetSizer(hbox)           

The DensityCtrl is too wide. and I’m not sure how to narrow it and still have the Sizer work as expected.

try changing it to:
hbox.Add(self.DensityCtrl, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)

In addition, my Frame contains two Panels in a VERTICAL BoxSizer. The one above which goes along the bottom, and one I draw on that fills the vast majority of the Frame. The panel that gets drawn on is a specific size, and often I find myself drawing below the top edge of my controls Panel. How can I resize the Frame based on the size of the two panels?

self.Fit() ?

Thank you! The first suggestion was perfect and much improves things.

Great–the “0” indicates make it a non-stretchable control, that’s the key.

The second one definitely changed the way things work, though it didn’t work the way I expected. I’m sure it’s a bug in my code somewhere. Digging now!

If you could post a small runnable sample, it’d be clearer to see what the problem might be. I probably should have asked for that instead of just mentioning .Fit().

Been working on that small runnable example, but it’s cutting down a fairly large chunk of code. Small = Easy. Small AND Runnable = more difficult.


Stand Fast,

tjg.


Stand Fast,
tjg

I thought adding these lines might help, but they didn't...

    def display_ecosystem(self, event=None):
        print "Ecosystem: display_ecosystem"
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event):
        event.Skip()
        dc = wx.PaintDC(self)

        dc.BeginDrawing()

        self.draw_grid(dc)
        self.repaint_ecosystem(dc)
        self.update_status_info()

        dc.EndDrawing()
        self.Refresh()

This allows the frame to be displayed, but it wildly repaints the
screen the whole time and seems caught in a loop. It's too much for
me to debug, unfortunately. Not sure what to suggest.

···

On Fri, Apr 11, 2008 at 7:29 PM, Timothy Grant <timothy.grant@gmail.com> wrote:

On Fri, Apr 11, 2008 at 4:07 PM, C M <cmpython@gmail.com> wrote:
>
>
>
>
>
>
> On Fri, Apr 11, 2008 at 6:53 PM, Timothy Grant <timothy.grant@gmail.com> > wrote:
> >
> >
> > On Wed, Apr 9, 2008 at 5:22 PM, Timothy Grant <timothy.grant@gmail.com> > > > wrote:
> > >
> > >
> > >
> > >
> > >
> > > On Wed, Apr 9, 2008 at 5:03 PM, C M <cmpython@gmail.com> wrote:
> > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > On Wed, Apr 9, 2008 at 6:21 PM, Timothy Grant > <timothy.grant@gmail.com> > > > wrote:
> > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > On Wed, Apr 9, 2008 at 3:11 PM, C M <cmpython@gmail.com> wrote:
> > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > > On Wed, Apr 9, 2008 at 6:02 PM, Timothy Grant > > > <timothy.grant@gmail.com> wrote:
> > > > > >
> > > > > > > I have a wx.SpinCtrl that I created and added to a horizontal
> > BoxSizer
> > > > > > >
> > > > > > > class Controls(wx.Panel):
> > > > > > > def __init__(self, parent):
> > > > > > > wx.Panel.__init__(self, parent)
> > > > > > > self.parent = parent
> > > > > > > self.GoButton = wx.Button(self, ID_GO_BUTTON, 'Go')
> > > > > > > self.ResetButton = wx.Button(self, ID_RESET_BUTTON,
> > 'Reset')
> > > > > > > self.SingleStepButton = wx.Button(self,
> > ID_SINGLESTEP_BUTTON, 'Step')
> > > > > > > self.DensityCtrl = wx.SpinCtrl(self,
ID_DENSITY_SPINNER)
> > > > > > > self.DensityCtrl.SetValue(10)
> > > > > > > print dir(self.DensityCtrl)
> > > > > > >
> > > > > > > hbox = wx.BoxSizer(wx.HORIZONTAL)
> > > > > > > hbox.Add(self.GoButton, 1, wx.ALIGN_LEFT |
> > wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
> > > > > > > hbox.Add(self.ResetButton, 1, wx.ALIGN_LEFT |
> > wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
> > > > > > > hbox.Add(self.SingleStepButton, 1, wx.ALIGN_LEFT |
> > wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
> > > > > > > hbox.Add(self.DensityCtrl, 1, wx.ALIGN_LEFT |
> > wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
> > > > > > > self.SetSizer(hbox)
> > > > > > >
> > > > > > > The DensityCtrl is too wide. and I'm not sure how to narrow it
and
> > still have the Sizer work as expected.
> > > > > > >
> > > > > >
> > > > > >
> > > > > > try changing it to:
> > > > > > hbox.Add(self.DensityCtrl, 0, wx.ALIGN_LEFT |
> > wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
> > > > > >
> > > > > >
> > > > > >
> > > > > > > In addition, my Frame contains two Panels in a VERTICAL
BoxSizer.
> > The one above which goes along the bottom, and one I draw on that fills
the
> > vast majority of the Frame. The panel that gets drawn on is a specific
size,
> > and often I find myself drawing below the top edge of my controls Panel.
How
> > can I resize the Frame based on the size of the two panels?
> > > > > > >
> > > > > >
> > > > > > self.Fit() ?
> > > > > >
> > > > >
> > > > >
> > > > > Thank you! The first suggestion was perfect and much improves
things.
> > > >
> > > >
> > > > Great--the "0" indicates make it a non-stretchable control, that's
the
> > key.
> > > >
> > > >
> > > > >
> > > > >
> > > > > The second one definitely changed the way things work, though it
> > didn't work the way I expected. I'm sure it's a bug in my code
somewhere.
> > Digging now!
> > > > >
> > > >
> > > > If you could post a small runnable sample, it'd be clearer to see
what
> > the problem might be. I probably should have asked for that instead of
just
> > mentioning .Fit().
> > > >
> > > >
> > > >
> > > Been working on that small runnable example, but it's cutting down a
> > fairly large chunk of code. Small = Easy. Small AND Runnable = more
> > difficult.
> > >
> > >
> > >
> > >
> > > --
> > > Stand Fast,
> > > tjg.
> >
> >
> > Well small and runnable ended up out of my reach. I'm attaching the code
for
> > my little version of Conway's game of life (something that has
fascinated me
> > since before I knew what programming was). It works pretty well, but I
hate
> > the way it resizes itself so any tips there would be greatly
appreciated.
> >
> > Also any other tips or nuances or just plain "your code sucks
because..."
> > comments are welcome.
>
> This doesn't run for me (on MSW). I get an error due to line 192:
> " wxPaintDC may be created only in EVT_PAINT handler!"
> _______________________________________________
> wxpython-users mailing list
> wxpython-users@lists.wxwidgets.org
> http://lists.wxwidgets.org/mailman/listinfo/wxpython-users
>

Well that's not fun!

I don't have a Windows box to test on so I'm at a loss.

Hi C M, Timothy,

[snip]

I thought adding these lines might help, but they didn't...

   def display_ecosystem(self, event=None):
       print "Ecosystem: display_ecosystem"
       self.Bind(wx.EVT_PAINT, self.OnPaint)

   def OnPaint(self, event):
       event.Skip()
       dc = wx.PaintDC(self)

       dc.BeginDrawing()

       self.draw_grid(dc)
       self.repaint_ecosystem(dc)
       self.update_status_info()

       dc.EndDrawing()
       self.Refresh()

This allows the frame to be displayed, but it wildly repaints the
screen the whole time and seems caught in a loop. It's too much for
me to debug, unfortunately. Not sure what to suggest.

The problem is the call to self.Refresh() at the bottom. Refresh() causes OnPaint to be fired, so that's why it gets into a loop. Remove that self.Refresh() call and I bet it will behave much more sanely after your changes. :slight_smile:

After that, though, I'd also change the calls to Ecosystem.display_ecosystem to call Ecosystem.Refresh() instead, except for the call in Ecosystem.__init__, which can be removed entirely. Make sure when you do this, you put the self.Bind(wx.EVT_PAINT, self.OnPaint) line in Ecosystem.__init__, because display_ecosystem won't be called any longer.

Regards,

Kevin

···

On Apr 11, 2008, at 4:39 PM, C M wrote:

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Thanks everyone for your input, I have gone through and made the suggested changes without really studying exactly what they do and why. That comes next.

I still face the issue that for some reason everything gets resized from something almost square to something tall and skinny. I’m not quite sure why this is. I think the “skinny” part comes from the fact that the controls in the Controls panel can be made to fit in a fairly narrow width when forced to. I’m still having trouble with the “tall” part though. I’m actually surprised at how many times things get resized before control ever returns to the user.

···

On Fri, Apr 11, 2008 at 6:44 PM, Kevin Ollivier kevin-lists@theolliviers.com wrote:

Hi C M, Timothy,

On Apr 11, 2008, at 4:39 PM, C M wrote:

[snip]

I thought adding these lines might help, but they didn’t…

def display_ecosystem(self, event=None):

   print "Ecosystem: display_ecosystem"

   self.Bind(wx.EVT_PAINT, self.OnPaint)

def OnPaint(self, event):

   event.Skip()

   dc = wx.PaintDC(self)



   dc.BeginDrawing()



   self.draw_grid(dc)

   self.repaint_ecosystem(dc)

   self.update_status_info()



   dc.EndDrawing()

   self.Refresh()

This allows the frame to be displayed, but it wildly repaints the

screen the whole time and seems caught in a loop. It’s too much for

me to debug, unfortunately. Not sure what to suggest.

The problem is the call to self.Refresh() at the bottom. Refresh() causes OnPaint to be fired, so that’s why it gets into a loop. Remove that self.Refresh() call and I bet it will behave much more sanely after your changes. :slight_smile:

After that, though, I’d also change the calls to Ecosystem.display_ecosystem to call Ecosystem.Refresh() instead, except for the call in Ecosystem.init, which can be removed entirely. Make sure when you do this, you put the self.Bind(wx.EVT_PAINT, self.OnPaint) line in Ecosystem.init, because display_ecosystem won’t be called any longer.

Regards,

Kevin


Stand Fast,
tjg.

Robin,

Thanks for the input, that explains a LOT. What kind of layout should I use if I want the controls to take a fixed amount of space and the panel Ecosystem Panel to be the variable amount of space?

···

On Mon, Apr 14, 2008 at 6:46 PM, Robin Dunn robin@alldunn.com wrote:

Timothy Grant wrote:

On Sun, Apr 13, 2008 at 6:08 PM, Robin Dunn <robin@alldunn.com mailto:robin@alldunn.com> wrote:

Timothy Grant wrote:





    I still face the issue that for some reason everything gets

    resized from something almost square to something tall and

    skinny. I'm not quite sure why this is. I think the "skinny"

    part comes from the fact that the controls in the Controls panel

    can be made to fit in a fairly narrow width when forced to. I'm

    still having trouble with the "tall" part though. I'm actually

    surprised at how many times things get resized before control

    ever returns to the user.





It's because you are calling Fit and the size you get is what the

sizer determined is the min size needed to display the widgets it

manages.  If you want the ecosystem widget to have a certain minimum

size then use its SetMinSize method.  Then the sizer will use that

in its calculations.





--    Robin Dunn

Software Craftsman

[http://wxPython.org](http://wxPython.org)  Java give you jitters?  Relax with wxPython!





_______________________________________________

wxpython-users mailing list

wxpython-users@lists.wxwidgets.org

mailto:wxpython-users@lists.wxwidgets.org

[http://lists.wxwidgets.org/mailman/listinfo/wxpython-users](http://lists.wxwidgets.org/mailman/listinfo/wxpython-users)

Thanks Robin,

That sort of makes sense, but I’m still baffled by the tall part (not the skinny part which was easily fixed by the SetMinSize

I added two more print statements, and the height changes and I don’t know why.

App Init

GenePool Init

Controls Init

Ecosystem Init

Ecosystem: set_grid_size_from_window_size

pw: 400 ph: 360 gw: 40 gh: 36

Model Init

Model: reset_cell_population

App: snap_to_size

400

540

Why is self.frame.GetClientSizeTuple() returning that height?

Obviously I can’t say for sure since I have no idea what numbers above are the GetClientSizeTuple values, nor did you send the updated code so I could see for sure, :wink: but it’s a safe bet that the cause is the proportion values you are using:

    vbox = wx.BoxSizer(wx.VERTICAL)

    vbox.Add(self.ecosystem, 100, wx.EXPAND)

    vbox.Add(self.controls, 8, wx.EXPAND)

You’re saying that the ecosystem gets 100 out of 108 shares of the available space, and that the controls get 8 out of 108 shares. Since the controls panel has a sizer that gives a min height then the ecosystem will end up being at least 12.5 times as high as the controls by default.

Robin Dunn

Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!


wxpython-users mailing list

wxpython-users@lists.wxwidgets.org

http://lists.wxwidgets.org/mailman/listinfo/wxpython-users


Stand Fast,
tjg.

Timothy Grant wrote:

Thanks for the input, that explains a LOT. What kind of layout should I use if I want the controls to take a fixed amount of space and the panel Ecosystem Panel to be the variable amount of space?

        vbox.Add(self.ecosystem, 1, wx.EXPAND)
        vbox.Add(self.controls, 0, wx.EXPAND)

This means that self.controls will be fixed in the vertical dimension, and that self.ecosystem will take all the remaining vertical space.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!