Productivity Sync Just another WordPress weblog

October 24, 2010

Quick before I forget! wxpython

Filed under: Uncategorized — admin @ 2:27 pm

A friend of mine asked if I could put together a visualisation program that would grab data for 33 x-y values from a keyboard and render them somehow.

My friend is a Windows guy and, although he can run ubuntu 10.10 in a vbox VM, he’s not a strong Linux guy.  Further the system he has is an old Window’s box.  I needed to get the visualisation to work on his system to be useful.  So, I looked to wx-Widgets and python to allow me to build a portable GUI.  Its nothing special but, it works well enough.

Not being a GUI programmer (for the last 11 years anyway) I wanted something that wouldn’t cost me more than an evening to two to get the UI up.

wxWigets http://www.wxwidgets.org/

wxGlaid http://wxglade.sourceforge.net/

python (2.7 used on Win2000) http://www.python.org/download/releases/2.7/

Hosting the application on his windows 2000 box mostly just worked.

On my dev system Ubunu 10.04.1LTS its running 2.6.5, I used synaptic to get wxGlaid.

Glade is kind of hard to get started with.  The notions of sub window containers and splitters is not too intuitive to me.  Steps to cobbling together the UI:

  1. add a frame
  2. add sizer, 2-slots-horizontal
  3. add sizer x 44-slots-vert
  4. add sizer y 44-slots-vert
  5. add wxGauge to a x slot
  6. add wxGauge to a y slot
  7. select view show properties, and go to the gauges’ layout tab and select wxEXPAND
  8. do a few guages then click on the app in the tree view, and go bac to the properties and punch the generate code button.

wxGlaid-isms

  • you need to see the properties of your widgets, but it doesn’t show it until you right click on the application frame_1 and select “show”.  right clicking elsewhere won’t do it.
  • the UI element for code generation is hidden under the application properties dialog box.
  • adding properties will add accesser calls to your object but not the actual accesser functions.
  • inserting a widget is done by first showing the frame, then clicking on the widget in the pallet, then clicking in the container widget you want your new widget to go.

wxGlaid is really buggy and the UI has quirks that are difficult to use.

  • Sometimes will generate incorrect python code after a bunch of fiddling about.
  • it seems to get into strange states and behave badly until restarted

There is just too many little “ism’s” with wxGlaid but, I was able to get it to create some code such that I could modify it to do what I needed it to do.

The last word I have on wxGlade is that its ok for a dialog box prototype for a newbee to use but, it sucks and hard to figure out and I’m board with trying to write about them here.

Threading issues with wx widgets.

After getting my code to run I implemented test code that would fire up a thread to change the values of the 88 guage’s in my window.  To my horror I found it would crash right away.  It seems that wx-widgets UI code is not thread safe for the re-draw’s and updates.  Those need to happen on the main thread of the UI event loop.  If you come in sideways on it it will fall over.

To get around this You need to make sure the updates happen within the thread context of the UI event loop.  You need to create a custom event message, message handler and bind them.  Then multi-threaded updating will work through event posting.

Snippets follow:

(UpdateMTSEvent, EVT_UPDATE_VALUES) = wx.lib.newevent.NewEvent()

def listen_thread(self):
 while True:
 event = self.get_key_event()
 evt = UpdateMTSEvent(key = event[0], xvalue = event[1], yvalue = event[2])
 wx.PostEvent(self, evt)

def __init__(self, *args, **kwds):
 # begin wxGlade: MyFrame.__init__
 kwds["style"] = wx.DEFAULT_FRAME_STYLE
 wx.Frame.__init__(self, *args, **kwds)
 self.YValues_staticbox = wx.StaticBox(self, -1, "Y Values")
 self.Xvalues_staticbox = wx.StaticBox(self, -1, "X Values")
 self.xvalues = []
 self.yvalues = []
 for i in xrange(44):
   gauge = wx.Gauge(self, -1, 256, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH)
   self.xvalues.append(gauge)
   gauge = wx.Gauge(self, -1, 256, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH)
   self.yvalues.append(gauge)
 self.__set_properties()
 self.__do_layout()
 self.Bind(EVT_UPDATE_VALUES, self.OnUpdate)
def OnUpdate(self, evt):
  self.xvalues[evt.key].SetValue(evt.xvalue)
  self.yvalues[evt.key].SetValue(evt.yvalue)
  self.Refresh(False)

Powered by WordPress