Re: SizedControls (SizedPanel) with StaticBox

46 views
Skip to first unread message

Brendan Simon (eTRIX)

unread,
Jul 16, 2009, 8:00:27 PM7/16/09
to wxPython-users
Robin Dunn wrote:
> Brendan Simon (eTRIX) wrote:
>> I want to have a StaticBox that 'encloses' a custom control.
>> I want to use SizedPanel because it's so cool and easy !!!
>>
>> Only problem is StaticBox doesn't have children like other windows.
>> It's 'contents' seem to be siblings.
>> That means that an instance of StaticBox and another control do not get
>> placed in the same sizer region, due to the way SizedPanel works.
>>
>> What I want is a dynamically sized StaticBox, where the contents also
>> get dynamically sized. The contents would be a control with any other
>> number of SizedPanels.
>>
>> Is there an elegant way to do this ??
>
> This is untested but looking at the code it looks like you can set the
> sizer type to "horizontal" or "vertical" to get a standard box sizer,
> and then replace it with a wx.StatiBoxSizer with a call to _SetNewSizer.
>
> The other option would be to teach SetSizerType to be able to create and
> use wx.StaticBoxSizers on its own, and submit a patch.


I tried your first suggestion, but still have issues. Code snippet below.

It seems that the only StaticBoxSizer constructor available in wxPython
relies on creating the StaticBox first and passing it to the constructor.

http://www.wxpython.org/docs/api/wx.StaticBoxSizer-class.html

Unfortunately creating the box adds it to the child of the sized panel,
and other controls are put along side the StaticBox, not inside the
static box.

I'm guessing that the second constructor method in the StaticBoxSizer
wxWidgets documentation would be the way to go. i.e. the constructor
creates the StaticBox.

http://docs.wxwidgets.org/stable/wx_wxstaticboxsizer.html#wxstaticboxsizer

Is this available in wxPython somehow ??

Maybe there is someway I can delete the 'child' but still have the sizer ??


class SBPanel( sc.SizedPanel ):

def __init__( self, parent, id, label='' ):
sc.SizedPanel.__init__( self, parent, id )

box = wx.StaticBox( self, label=label )
box.SetSizerProps( halign='center', expand=True, proportion=1 )
sizer = wx.StaticBoxSizer( box, orient=wx.HORIZONTAL )
self._SetNewSizer( sizer )

b1 = wx.Button(self, -1, 'b1')
t1 = wx.TextCtrl(self, -1, 't1')
b2 = wx.Button(self, -1, 'b2')

self.Fit()
self.SetMinSize( self.GetSize() )

Brendan_Simon.vcf

Brendan Simon (eTRIX)

unread,
Jul 16, 2009, 9:35:31 PM7/16/09
to wxPytho...@googlegroups.com
Brendan Simon (eTRIX) wrote:
> Robin Dunn wrote:
>> Brendan Simon (eTRIX) wrote:
>>> I want to have a StaticBox that 'encloses' a custom control.
>>> I want to use SizedPanel because it's so cool and easy !!!
>>> Is there an elegant way to do this ??

>> This is untested but looking at the code it looks like you can set the
>> sizer type to "horizontal" or "vertical" to get a standard box sizer,
>> and then replace it with a wx.StatiBoxSizer with a call to _SetNewSizer.
>>
>> The other option would be to teach SetSizerType to be able to create and
>> use wx.StaticBoxSizers on its own, and submit a patch.
>
>
> I tried your first suggestion, but still have issues. Code snippet below.
>

> Unfortunately creating the box adds it to the child of the sized panel,
> and other controls are put along side the StaticBox, not inside the
> static box.
>

> Maybe there is someway I can delete the 'child' but still have the sizer ??

I got it to work by overriding the _SetNewSizer() method, so that it
didn't add the StaticBox control to the sizer :)

Only problem now is I get a segmentaion fault when exiting the program :(

I'm guessing that the StaticBox is being destroyed while the sizer is
still in use -- or something of that nature ???

Any ideas where to go from here so that it exits cleanly ???

class SBPanel( sc.SizedPanel ):

def __init__( self, parent, id, label = 'SBPanel' ):


sc.SizedPanel.__init__( self, parent, id )

box = wx.StaticBox( self, label = label )


box.SetSizerProps( halign='center', expand=True, proportion=1 )

self.boxId = box.GetId()
sizer = wx.StaticBoxSizer( box, orient = wx.HORIZONTAL )
self._SetNewSizer( sizer )

b1 = wx.Button(self, -1, 'b1')
t1 = wx.TextCtrl(self, -1, 't1')
b2 = wx.Button(self, -1, 'b2')

self.Fit()
self.SetMinSize( self.GetSize() )

def _SetNewSizer(self, sizer):
props = {}
for child in self.GetChildren():
childId = child.GetId()
props[childId] = child.GetSizerProps()
self.GetSizer().Detach(child)

wx.PyPanel.SetSizer(self, sizer)

for child in self.GetChildren():
childId = child.GetId()
if childId != self.boxId :
self.GetSizer().Add(child)
child.SetSizerProps(props[childId])


Brendan_Simon.vcf

Mike Driscoll

unread,
Jul 17, 2009, 9:17:04 AM7/17/09
to wxPython-users
Hi,

On Jul 16, 8:35 pm, "Brendan Simon (eTRIX)"
>  Brendan_Simon.vcf


I don't see anything obvious in here that would be causing this issue.
Are you using threads or a taskbar icon? Do you have any frames or
dialogs that you're hiding instead of destroying?

- Mike

Robin Dunn

unread,
Jul 17, 2009, 2:17:30 PM7/17/09
to wxPytho...@googlegroups.com

Ah, I forgot that the AddChild method is doing that magic behind the
scenes... I think that the way I would handle this is to override
AddChild and tweak it such that when it is being called for the
staticbox that will be used for the sizer then just call
wx.PyPanel.AddChild directly, otherwise call SizedPanel.AddChild so it
will add the child to the sizer.


>
> I'm guessing that the second constructor method in the StaticBoxSizer
> wxWidgets documentation would be the way to go. i.e. the constructor
> creates the StaticBox.
>
> http://docs.wxwidgets.org/stable/wx_wxstaticboxsizer.html#wxstaticboxsizer
>
> Is this available in wxPython somehow ??

No, but it would have the same problem even if it was available. It
still needs to create a staticbox widget as a child of the panel, and
when it does the panel's AddChild will still be called.

--
Robin Dunn
Software Craftsman
http://wxPython.org

Robin Dunn

unread,
Jul 17, 2009, 2:17:57 PM7/17/09
to wxPytho...@googlegroups.com
Brendan Simon (eTRIX) wrote:
> Brendan Simon (eTRIX) wrote:
>> Robin Dunn wrote:
>>> Brendan Simon (eTRIX) wrote:
>>>> I want to have a StaticBox that 'encloses' a custom control.
>>>> I want to use SizedPanel because it's so cool and easy !!!
>>>> Is there an elegant way to do this ??
>
>>> This is untested but looking at the code it looks like you can set the
>>> sizer type to "horizontal" or "vertical" to get a standard box sizer,
>>> and then replace it with a wx.StatiBoxSizer with a call to _SetNewSizer.
>>>
>>> The other option would be to teach SetSizerType to be able to create and
>>> use wx.StaticBoxSizers on its own, and submit a patch.
>>
>> I tried your first suggestion, but still have issues. Code snippet below.
>>
>> Unfortunately creating the box adds it to the child of the sized panel,
>> and other controls are put along side the StaticBox, not inside the
>> static box.
>>
>> Maybe there is someway I can delete the 'child' but still have the sizer ??
>
> I got it to work by overriding the _SetNewSizer() method, so that it
> didn't add the StaticBox control to the sizer :)
>
> Only problem now is I get a segmentaion fault when exiting the program :(
>
> I'm guessing that the StaticBox is being destroyed while the sizer is
> still in use -- or something of that nature ???
>
> Any ideas where to go from here so that it exits cleanly ???

There is probably something that is still referring to the old sizer and
is trying to destroy it a 2nd time at shutdown.

Brendan Simon (eTRIX)

unread,
Jul 19, 2009, 6:38:05 AM7/19/09
to wxPytho...@googlegroups.com


The following solves the segfault on closing the application.
Basically create the static box, and then detach it from the 'original'
sizer immediately.

box = wx.StaticBox( self, label = label )

self.GetSizer().Detach(box)

Also put in additional check in _SetNewSizer() to not detach the static
box child (as it isn't attached anymore).

Of course the "proper" way to do this is to modify the SetSizerType()
method in SizedPanel and submit a patch. I will work on that :)


import wx
import wx.lib.sized_controls as wxSC

class SBPanel( wxSC.SizedPanel ):

def __init__( self, parent, id, label = '' ):
wxSC.SizedPanel.__init__( self, parent, id )

self.SetSizerType( type = 'staticbox', label = label )

#b1 = wx.Button( self, wx.ID_ANY, 'b1' )
#t1 = wx.TextCtrl( self, wx.ID_ANY, 't1' )
#b2 = wx.Button( self, wx.ID_ANY, 'b2' )

self.Fit()
self.SetMinSize( self.GetSize() )

def SetSizerType( self, type, label ):
"Override method in SizedPanel to support StaticBoxSizer."

box = wx.StaticBox( self, label = label )

# Detach staticBox from the original sizer to avoid
# segfault on destruction.
self.GetSizer().Detach(box)

self.boxId = box.GetId()
sizer = wx.StaticBoxSizer( box, orient = wx.HORIZONTAL )
self._SetNewSizer( sizer )

def _SetNewSizer(self, sizer):
"Override method in SizedPanel to support StaticBoxSizer."

wxSC.SizedPanel.sizerType = sizer

props = {}
for child in self.GetChildren():
childId = child.GetId()

if childId != self.boxId :

Brendan_Simon.vcf
Reply all
Reply to author
Forward
0 new messages