wx.WrapSizer.IsSpaceItem fails

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

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.

···

'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.

--
Robin Dunn
Software Craftsman

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

···

Il giorno mercoledì 12 luglio 2017 21:34:29 UTC+2, Robin Dunn ha scritto:

‘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

Probably.

···

'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.

--
Robin Dunn
Software Craftsman