Greetings:
I am trying to add and remove widgets dynamically in response to button
events, e.g. creating an arbitrary number of TextCtrl widgets. This is
easily accomplished; however, I can’t get the resizing to work correctly
or consistently, and when the panel on which the widgets are placed is
a ScrolledWindow, large regions of the panel are lost when redrawing if the
viewable area is less than the total panel size. I’ve appended the most
minimal example I could come up with below this message. I’ve tried
fiddling with Fit() and the various scrollarea methods, but no luck so
far. Refreshing and resizing the frame after each widget is drawn does
keep the entire panel accessible, but this causes other problems instead.
For what it’s worth, when I’m doing this in the context of a modal dialog
window instead of a Frame/ScrolledWindow combination, the window size is
not always re-adjusted properly (sometimes it resizes, sometimes it doesn’t;
this doesn’t seem to follow any pattern).
Other problems:
- Sometimes it simply refuses to redraw the scrollbars. I’ve confirmed
that the size obtained by GetSizeTuple() is what it should be, but
SetScrollbars() is not working. (Some of the time, that is.) Here’s
what this looks like:
http://ucxray.berkeley.edu/~nat/img/wx_cutoff.png
- I seem to be left with ghost widgets when I try to delete a section.
I’m actually only deleting the sizer that contains them, because this should
destroy the widgets too. (At any rate, if I try to Destroy() them
individually, I get a wx._core.PyDeadObjectError. If I try to destroy
the widgets but not the sizer, it gets weirder.)
http://ucxray.berkeley.edu/~nat/img/wx_ghost.png
I’ve been doing most of my development on Mac (native widgets, not X11), but
I get similar results with Linux. (Slightly worse, actually - it segfaults
when I close the program.) We appear to be using wxPython 2.8.0 on both
systems (wrapping GTK2 on Linux).
Any advice would be greatly appreciated.
#— begin code
import wx
class testApp (wx.App) :
def OnInit (self) :
frame = testFrame(self)
self.SetTopWindow(frame)
frame.Show()
return True
class testFrame (wx.Frame) :
def init (self, parent) :
wx.Frame.init(self, None, -1, “Test frame”)
self.widget_area = scrollArea(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.widget_area, 1, wx.EXPAND, 5)
self.SetAutoLayout(1)
self.SetSizer(self.sizer)
self.Fit()
def resetLayout (self) :
pass
class scrollArea (wx.ScrolledWindow) :
def init (self, parent) :
wx.ScrolledWindow.init(self, parent, -1, style=wx.SUNKEN_BORDER)
self.panel = self
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.panel.SetSizer(self.main_sizer)
self.frame = parent
self.widget_handler = widgetCopier(self)
self.main_sizer.Add(self.widget_handler)
self.widget_handler.newCopy()
self.resetLayout()
def resetLayout (self) :
self.main_sizer.Fit(self.panel)
(w, h) = self.panel.GetSizeTuple()
self.SetScrollbars(1, 1, w, h)
self.frame.resetLayout()
class widgetCopier (wx.BoxSizer) :
current_sizer = None
widget_stack = []
def init (self, parent) :
wx.BoxSizer.init(self, wx.VERTICAL)
self.parent = parent
add_btn = wx.Button(self.parent.panel, -1, “Add copy”)
del_btn = wx.Button(self.parent.panel, -1, “Delete copy”)
self.btns = wx.BoxSizer(wx.HORIZONTAL)
self.btns.Add(del_btn, 0, wx.RIGHT, 5)
self.btns.Add(add_btn)
self.parent.frame.Bind(wx.EVT_BUTTON, self.newCopy, add_btn)
self.parent.frame.Bind(wx.EVT_BUTTON, self.deleteCopy, del_btn)
self.newCopy()
def setButtons (self) :
if self.current_sizer != None :
self.current_sizer.Add(self.btns, 0, wx.ALL, 5)
def detachButtons (self) :
if self.current_sizer != None :
self.current_sizer.Detach(self.btns)
def newCopy (self, event=None) :
self.detachButtons()
new_copy = wx.BoxSizer(wx.HORIZONTAL)
new_copy_widget = wx.CheckBox(self.parent.panel, -1,
“This is checkbox %d” % (len(self.widget_stack) + 1))
new_copy.Add(new_copy_widget, 0, wx.ALL, 5)
self.Add(new_copy, 0, wx.ALL, 5)
self.widget_stack.append(new_copy)
self.current_sizer = new_copy
self.setButtons()
self.Layout()
self.parent.resetLayout()
def deleteCopy (self, event=None) :
self.detachButtons()
if len(self.widget_stack) > 0 :
last_copy = self.widget_stack.pop()
self.Detach(last_copy)
last_copy.Destroy()
if len(self.widget_stack) > 0 :
self.current_sizer = self.widget_stack[-1]
else :
self.current_sizer = None
self.setButtons()
self.Layout()
self.parent.resetLayout()
if name == “main” :
prog = testApp(0)
prog.MainLoop()
#—end