Reputation: 1856
I'm teaching myself (Wx) Python and got stuck. I want to create a child window that has a recurring set of information inside of my TestFrame, which contains most of my code. The problem is, it only shows one widget in my code. I am trying to figure out the following, in order of importance to me.
**Note that this code is an extension to this page.*
Thank you for your help. If allowed/appropriate, I'm willing to contribute $5 via Paypal to the winner if you PM me.
import wx
class AddBox(wx.Window):
def __init__(self, parent):
wx.Window.__init__(self, parent)
pbox = wx.BoxSizer(wx.VERTICAL)
controlback = wx.Button(self, label="Back")
controlforward = wx.Button(self, label="Forward")
pbox.AddMany([(controlback, 1, wx.ALL), (controlforward, 1, wx.ALL)])
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, size=(1000, 550))
self.Bind(wx.EVT_SIZE, self.OnSize)
pbox0 = wx.BoxSizer(wx.VERTICAL)
controlback0 = wx.Button(self, label="Back0")
controlforward0 = wx.Button(self, label="Forward0")
pbox0.AddMany([(controlback0, 1, wx.ALL), (controlforward0, 1, wx.ALL)])
pbox2 = wx.BoxSizer(wx.VERTICAL)
self.scrolling_window = wx.ScrolledWindow( self )
self.scrolling_window.SetScrollRate(1,6)
self.scrolling_window.EnableScrolling(True,True)
self.sizer_container = wx.BoxSizer( wx.VERTICAL )
self.sizer = wx.BoxSizer( wx.VERTICAL )
self.sizer_container.Add(self.sizer,1,wx.CENTER,wx.EXPAND)
self.child_windows = []
for i in range(0,8):
wind = AddBox(self.scrolling_window)
self.sizer.Add(wind, 0, wx.CENTER|wx.ALL, 5)
self.child_windows.append(wind)
self.scrolling_window.SetSizer(self.sizer_container)
#self.Layout() #not needed?
pbox2.AddMany([(self.sizer_container, 1, wx.ALL)])
def OnSize(self, event):
self.scrolling_window.SetSize(self.GetClientSize())
if __name__=='__main__':
app = wx.PySimpleApp()
f = TestFrame()
f.Show()
app.MainLoop()
Upvotes: 1
Views: 1724
Reputation: 33071
The code here is pretty convoluted and hard to follow. You almost never need to use wx.Window. In fact, in almost 6 years of using wxPython, I have NEVER used it directly. PySimpleApp is deprecated as well. Anyway, I cleaned up the code a bunch and re-did it below. I'm not sure if this is what you're looking for or not though. Also note that I swapped out ScrolledWindow for ScrolledPanel as I think the latter is easier to use:
import wx
import wx.lib.scrolledpanel as scrolled
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size=(1000, 550))
panel = wx.Panel(self)
mainSizer = wx.BoxSizer(wx.VERTICAL)
pbox0 = wx.BoxSizer(wx.VERTICAL)
controlback0 = wx.Button(panel, label="Back0")
controlforward0 = wx.Button(panel, label="Forward0")
pbox0.Add(controlback0, 0, wx.ALL)
pbox0.Add(controlforward0, 0, wx.ALL)
mainSizer.Add(pbox0)
self.scrolling_window = scrolled.ScrolledPanel( panel )
self.scrolling_window.SetAutoLayout(1)
self.scrolling_window.SetupScrolling()
self.sizer = wx.BoxSizer( wx.VERTICAL )
self.child_windows = []
for i in range(0,8):
wind = self.addBox()
self.sizer.Add(wind, 0, wx.CENTER|wx.ALL, 5)
self.scrolling_window.SetSizer(self.sizer)
mainSizer.Add(self.scrolling_window, 1, wx.EXPAND)
panel.SetSizer(mainSizer)
def addBox(self):
pbox = wx.BoxSizer(wx.VERTICAL)
controlback = wx.Button(self.scrolling_window, label="Back")
controlforward = wx.Button(self.scrolling_window, label="Forward")
pbox.AddMany([(controlback, 0, wx.ALL), (controlforward, 0, wx.ALL)])
return pbox
def OnSize(self, event):
self.scrolling_window.SetSize(self.GetClientSize())
if __name__=='__main__':
app = wx.App(False)
f = TestFrame()
f.Show()
app.MainLoop()
You should also take a look at the Widget Inspection Tool. It will help you figure out layout problems like this: http://wiki.wxpython.org/Widget%20Inspection%20Tool
EDIT: I think the code above takes care of items #1 and 2. For #3, see the following article I wrote last year: http://www.blog.pythonlibrary.org/2011/09/20/wxpython-binding-multiple-widgets-to-the-same-handler/
Basically you bind in the loop itself and then in the event handler, you can use event.GetEventObject() to return the calling widget and set its value or whatever. As for your 4th question, I would say no, you don't need the OnSize method. You almost never need to override that in wxPython and I certainly didn't in my example code.
Upvotes: 1
Reputation: 6055
I just have an answer to 3 for now: Assign to each dynamically created widget an ID, store this ID in a dictionary ({id : widget }) and pass as the callback function a lambda-function or use functools.partial to pass the ID to the "real" callback. (of course you can pass the widget directly over the lambda-function, but I like to have instances to the created widgets somewhere, if I need to access these sometime)
def __init__(...):
self.event_dispatch = dict()
...
for id in xrange(500, 508):
wind = AddBox(self.scrolling_window, id)
...
self.event_dispatch[id] = wind
self.scrolling_window.Bind(wx.MY_EVENT, lambda evt: self.on_event(evt, id), id=id)
def on_event(event, id):
widget = self.event_dispatch[id]
# do something with widget
Upvotes: 0