Sizers look a little complex at first, but they can make your component layouts a lot simpler. The wx.GridSizer() is particularly well suited for a bunch of similar widgets generated with a for loop. In this case I used the gridsizer for the buttons of a simple calculator. The buttons simply keep wrapping from left to right, down a notch then left to right again ...
# create a calulator button layout with wx.GridSizer()
# then add a few things to form a tiny wxPython calculator
import wx
class MyFrame(wx.Frame):
"""make a frame, inherits wx.Frame"""
def __init__(self):
# create a frame/window, no parent
wx.Frame.__init__(self, None, wx.ID_ANY, 'wx_Calc',
pos=(300, 150), size=(185, 160))
self.SetBackgroundColour('green')
# main sizer
vsizer = wx.BoxSizer(wx.VERTICAL)
self.edit = wx.TextCtrl(self, -1, value="", size=(165, 20))
# follows layout of calculator keys
self.btn_list = [
'7', '8', '9', '/', 'c',
'4', '5', '6', '*', 'bs',
'1', '2', '3', '-', '**',
'0', '.', '=', '+', 'neg'
]
# wx.GridSizer(rows, cols, vgap, hgap)
gsizer = wx.GridSizer(4, 5, 2, 2)
self.btn = range(len(self.btn_list))
for ix, b_label in enumerate(self.btn_list):
# set up a consecutive unique id for each button
id = 1000 + ix
self.btn[ix] = wx.Button(self, id, label=b_label, size=(20, 20))
# the gridsizer fills left to right one row at a time
gsizer.Add(self.btn[ix], 0, wx.ALL|wx.EXPAND, border=2)
self.btn[ix].Bind(wx.EVT_BUTTON, self.btnClick)
# now add the whole thing to the main sizer and set it
vsizer.Add(self.edit, 0, wx.EXPAND)
vsizer.Add(gsizer, 0, wx.EXPAND)
self.SetSizer(vsizer)
def btnClick(self, event):
# get the label of the button clicked
label = self.btn_list[event.GetId() - 1000]
e_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '-', '*', '/', '**', '.']
if label in e_list:
self.edit.SetValue(self.edit.GetValue() + label)
elif label == 'neg':
# negate, note eval() takes care of double negate
self.edit.SetValue('-' + self.edit.GetValue())
elif label == 'c':
# clear
self.edit.SetValue('')
elif label == 'bs':
# backspace
self.edit.SetValue(self.edit.GetValue()[:-1])
elif label == '=':
str1 = self.edit.GetValue()
# prevent folks from being nasty with eval()
if not str1 or str1[0] not in '0123456789-+.':
self.edit.SetValue('unrecognized operation')
return
while str1[0] == '0':
# avoid leading zero (octal) error with eval()
str1 = str1[1:]
if '/' in str1 and '.' not in str1:
# turn into floating point division
str1 = str1 + '.0'
try:
self.edit.SetValue(str(eval(str1)))
except ZeroDivisionError:
self.edit.SetValue('division by zero error')
else:
self.edit.SetValue('unrecognized operation')
app = wx.App(0)
# create MyFrame instance and show the frame
MyFrame().Show()
app.MainLoop()