wx.WrapSizer.IsSpaceItem fails

46 views
Skip to first unread message

ricpol

unread,
Jul 12, 2017, 10:39:08 AM7/12/17
to wxPython-users
Has anyone actually tried out wx.WrapSizer.IsSpaceItem? It is now overridable in Phoenix, but it just doesn't work for me...

class MyWrapSizer(wx.WrapSizer):
   
def IsSpaceItem(self, item):
        window
= item.GetWindow()
       
if isinstance(window, wx.StaticText):
           
return True  # if sizer item has a static text inside, then pretend it's a space
       
return wx.WrapSizer.IsSpaceItem(self, item)

class MainFrame(wx.Frame):
   
def __init__(self, *a, **k):
        wx
.Frame.__init__(self, *a, **k)
        p
= wx.Panel(self)
        sizer
= MyWrapSizer(wx.HORIZONTAL, wx.REMOVE_LEADING_SPACES)
       
for _ in range(5):
            sizer
.Add(wx.Button(p, size=(50, 50)))
        sizer
.Add(wx.StaticText(p, -1, 'Hello!')) # now this one should be treated as space
       
for _ in range(5):
            sizer
.Add(wx.Button(p, size=(50, 50)))
        p
.SetSizer(sizer)

This should be a reasonable thing to ask - yet if fails with

wx._core.wxAssertionError: C++ assertion "!sizer || m_containingSizer != sizer" failed at ..\..\src\common\wincmn.cpp(2470) in wxWindowBase::SetContainingSizer(): Adding a window to the same sizer twice?

The above exception was the direct cause of the following exception:

SystemError: <class 'wx._core.SizerItem'> returned a result with an error set

Please note that re-creating the original behaviour works fine:

class MyWrapSizer(wx.WrapSizer):
   
def IsSpaceItem(self, item):
       
return item.IsSpacer() # this works like a charm

However, testing for SizerItem.IsSizer (instead of IsSpacer) behaves erratically depending of the actual content of the (sub)sizer:

class MyWrapSizer(wx.WrapSizer):
   
def IsSpaceItem(self, item):
       
return item.IsSizer()

class MainFrame(wx.Frame):
   
def __init__(self, *a, **k):
        wx
.Frame.__init__(self, *a, **k)
        p
= wx.Panel(self)
        sizer
= MyWrapSizer(wx.HORIZONTAL, wx.REMOVE_LEADING_SPACES)
       
for _ in range(5):
            sizer
.Add(wx.Button(p, size=(50, 50)))
        s
= wx.BoxSizer()
        s
.Add(wx.TextCtrl(p, -1, 'Hello!'))  
        sizer
.Add(s) # this should be a space, now
       
for _ in range(5):
            sizer
.Add(wx.Button(p, size=(50, 50)))
        p
.SetSizer(sizer)

This doesn't fail, but it doesn't quite work either. If you put a StaticText inside the sub-sizer instead, it looks better, but still can't wrap it nicely.

My guess is, even if wx.WrapSizer.IsSpaceItem is indeed overridable, the behind-the-scenes machinery of wx.Sizer.Add is just too much for wxPython to tamper with.
Or - it's just me missing something obvious here?

riccardo

Robin Dunn

unread,
Jul 12, 2017, 3:34:29 PM7/12/17
to wxpytho...@googlegroups.com
'ricpol' via wxPython-users wrote:
> My guess is, even if wx.WrapSizer.IsSpaceItem is indeed overridable,
> the behind-the-scenes machinery of wx.Sizer.Add is just too much for
> wxPython to tamper with.

More or less. The base RecalcSizes calls window.SetContainingSizer if
the item is a window, but that code path is avoided if IsSpaceItem
returns True, and since the containing sizer is already set on that item
then the assertion error is triggered. You can avoid that by calling
window.SetContainingSize(None) yourself.

However even with that addition I don't think you can do what you are
trying to do with this code. The static text widget will still be
visible, it just won't be used for calculating the positions and sizes
of the other items, doing that with spacer items is okay since they
don't draw anything.

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

ricpol

unread,
Jul 13, 2017, 4:03:21 AM7/13/17
to wxPython-users
Thanks for clarifying.
I've given SetContainingSizer a run... Well it tries very hard to keep the house clean, but still fails in various ways depending on the actual managed widget, plus it almost always crashes on exit.

> I don't think you can do what you are trying to do with this code

I was just looking for possible use cases for wx.WrapSizer.IsSpaceItem but it seems this function is just too hard to set up to be useful. Yes, maybe you could work your black magic overriding RecalcSizes too, but the game isn't worth the candle here.
I can't find any example in wxWidgets too... my hunch is that it's just a not-so-carefully-designed api, that was added to the mix because who knows, someone might find a use for it one day.


r

Robin Dunn

unread,
Jul 18, 2017, 10:27:15 PM7/18/17
to wxpytho...@googlegroups.com
'ricpol' via wxPython-users wrote:
> I can't find any example in wxWidgets too... my hunch is that it's
> just a not-so-carefully-designed api, that was added to the mix
> because who knows, someone might find a use for it one day.
>

Probably.
Reply all
Reply to author
Forward
0 new messages