I spent some time today picking up wxPython to add a GUI to Nessie. Here's a few things I learned:
wxPython defaults to logging errors into a wx window on Windows and Mac. That's pretty useless if your application crashes and the window disappears immediately. To redirect output to your console use:
wxPython defaults to logging errors into a wx window on Windows and Mac. That's pretty useless if your application crashes and the window disappears immediately. To redirect output to your console use:
wx.App(redirect=False)The wxPython style guide suggests using sizers for laying out your application. The most useful of these is the GridBagSizer (basically a table where items can span multiple cells). Unfortunately, the API for this sizer is a bit cumbersome. It requires you to specify the coordinates for each item in the grid. That's fine until you want to insert a new row and end up shifting all the following coordinates by one. I wrote a quick factory wrapper around the GridBagSizer that I think makes for a nicer API.
class GridBagSizerFactory(object):With this factory, row and column numbers are handled automatically so adding new items is a cinch. Here's a small snippet from the Nessie GUI I'm working on:
def __init__(self, hgap, vgap):
self.sizer = wx.GridBagSizer(hgap, vgap)
self._row = 0
self._col = 0
def _Add(self, obj, *args, **kwargs):
self.sizer.Add(obj, (self._row, self._col), *args, **kwargs)
def Add(self, *args, **kwargs):
self._Add(*args, **kwargs)
self.NewCol()
def AddGrowable(self, *args, **kwargs):
self._Add(*args, **kwargs)
self.sizer.AddGrowableCol(self._col)
self.NewCol()
def NewCol(self):
self._col += 1
def NewRow(self):
self._col = 0
self._row += 1
def NewGrowableRow(self):
self.NewRow()
self.sizer.AddGrowableRow(self._row)
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
add_node_btn = wx.Button(self, label='Add Node')
chat_log_txt = wx.TextCtrl(self, style=wx.TE_MULTILINE)
nodes_lbx = wx.ListBox(self, choices=['foo', 'bar', 'baz'])
chat_txt = wx.TextCtrl(self, size=(-1, -1))
chat_txt.Bind(wx.EVT_KEY_DOWN, self.Chat)
sizer_factory = GridBagSizerFactory(5, 5)
sizer_factory.Add(add_node_btn, (1, 1))
sizer_factory.NewGrowableRow()
sizer_factory.AddGrowable(chat_log_txt, (1, 1), wx.EXPAND)
sizer_factory.Add(nodes_lbx, (1, 1), wx.EXPAND)
sizer_factory.NewRow()
sizer_factory.Add(chat_txt, (1, 2), wx.EXPAND)
self.SetSizer(sizer_factory.sizer)
self.Show()