wxpython: scrolled panel magics
today is a good day to create some wxpython scrolled panels; what i had imagined is a scrolled panel with client size 256x256 and virtual size 1024x1024, using a wxpython 4.0.7 gtk2 build;
something that does not work
this is what i came up with earlier; very natural no brainer:
#!/usr/bin/env python3
'''
show a scrolled panel with client size 256x256 and virtual size 1024x1024;
'''
from wx.lib.scrolledpanel import ScrolledPanel
import wx
def OnScrollWin(evt):
panel = evt.GetEventObject()
frame = panel.GetParent()
## expect: `frame=(..., ...), panel=(256, 256)`
print(f'frame={frame.GetClientSize()}, panel={panel.GetClientSize()}')
evt.Skip()
app = wx.App()
frame = wx.Frame(None)
panel = ScrolledPanel(frame)
panel.SetMinClientSize((256, 256))
panel.SetScrollbars(1, 1, 1024, 1024)
panel.Bind(wx.EVT_SCROLLWIN, OnScrollWin)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 0)
frame.SetSizer(sizer)
frame.Fit()
frame.Layout()
frame.Center()
frame.Show()
app.MainLoop()
unfortunately, this does not work; as i wrote it i was looking for a client size of 256x256 when scrolling; but the program always gave wrong result;
something that does work
then i realized there must be some magics; after some trial and error, this is what i came up with later that finally works:
#!/usr/bin/env python3
'''
show a scrolled panel with client size 256x256 and virtual size 1024x1024;
'''
from wx.lib.scrolledpanel import ScrolledPanel
import wx
def OnScrollWin(evt):
panel = evt.GetEventObject()
frame = panel.GetParent()
## expect: `frame=(..., ...), panel=(256, 256)`
print(f'frame={frame.GetClientSize()}, panel={panel.GetClientSize()}')
evt.Skip()
app = wx.App()
frame = wx.Frame(None)
frame.SetClientSize(frame.GetClientSize()) # magic_1
panel = ScrolledPanel(frame)
panel.SetMinClientSize((256, 256))
panel.SetScrollbars(1, 1, 1024, 1024)
panel.Bind(wx.EVT_SCROLLWIN, OnScrollWin)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 0)
frame.SetSizer(sizer)
frame.Show() # magic_2
panel.SetMinClientSize((256, 256)) # magic_3
frame.Fit()
frame.Layout()
frame.Center()
app.MainLoop()
there are 3 magics that made it work:
-
call
SetClientSize
after frame creation;setting-a-getting really looks like a (harmless) noop, but is actually no noop;
-
call
Show
beforeFit
andLayout
;i always considered early
Show
to be smelly code, cuz it displays partial result; but in this case i have no other way to get it work; my conjecture is that the scrollbar size is only known after the frame is shown (because it is native), but this is only my guess; -
call
SetMinClientSize
on panel, again;yup, just call it again after frame is shown; who knows why the first call no longer works? just call it, again;
to be honest, these are real magics; i could not explain why; one needs magics to deal with scrolled panels, really;