Back to tutorial index

wxPython

wxPython is a wrapper for the cross-platform GUI API wxWidgets, which have a native look and file. Here are few resources for working with it.

Installation

A very nice guide to wxPython

http://zetcode.com/wxpython/

A sample wxPython app

A GCode-STL viewer in Python (wxPython for the GUI and PyOpenGl for the 3D visualization): https://github.com/dkobozev/tatlin

A wxPython GUI builder

There are manu GUI builders, my favourite is wxFormBuilder. But only from version 3.3 it exports the code in Python, so here's the link to the right folder: http://sourceforge.net/projects/wxformbuilder/files/wxformbuilder-nightly/3.3.04-beta/. Remember that the app export only the classes that you create/customize, you then have to create objects and launch the app, for example with a code like this:

# -*- coding: utf-8 -*-

# Main library
import wx
# This is the file as exported from wxFormBuilder. It is just a .py file in the same folder
import wxidelib

# Create an app
ex = wx.App()
# Create a frame from my custom class
ex1 = wxidelib.MyFrame1(None)
# Show the frame! Otherwise it won't work. wxFormBuilder does not add this
ex1.Show()
# Initialize the event loop
ex.MainLoop()

Reading data from serial and drawing it on wxPython

The important thing when reading data from serial, is to bind the reading of the data to a timer, so that the app will read data only at a certain rate and it won't crash. Here's a basic example that draws a line and a rectangle from the wxPython API (but you can use other Python libraries for drawing, like Matplotlib or Cairo).

# -*- coding: utf-8 -*-
# Author: Massimo Menichinelli
# Homepage: http://www.openp2pdesign.org
# License: MIT
#
import wx
import serial
# A new custom class that extends the wx.Frame
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title=title,
size=(250, 150))
# Attach the paint event to the frame
self.Bind(wx.EVT_PAINT, self.OnPaint)
# Create a timer for redrawing the frame every 100 milliseconds
self.Timer = wx.Timer(self)
self.Timer.Start(100)
self.Bind(wx.EVT_TIMER, self.OnPaint)
# Show the frame
self.Centre()
self.Show()
def OnPaint(self, event=None):
# Create the paint surface
dc = wx.PaintDC(self)
# Refresh the display
self.Refresh()
# Get data from serial port
value = arduino.readline()
# Draw the serial data
# Set up colors:
thickness = 4
border_color = "#990000"
fill_color = "#FF944D"
dc.SetPen(wx.Pen(border_color, thickness))
dc.SetBrush(wx.Brush(fill_color))
# Draw a line
dc.DrawLine(50, 40, 50+value, 40)
# Draw a rectangle
dc.DrawRectangle(50,50,value,50)
# Main program
if __name__ == '__main__':
# Connect to serial port first
try:
arduino = serial.Serial('/dev/tty.usbmodem1421', 9600)
except:
print "Failed to connect"
exit()
# Create and launch the wx interface
app = wx.App()
MyFrame(None, 'Serial data test')
app.MainLoop()
# Close the serial connection
arduino.close()

Drawing serial data with wxPython+Matplotlib

You can also include Matplotlib visualizations in wxPython. Here are some sample codes: 01, 02. Here's my code, that reads from serial data:

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
import wx
import serial
# Import matplotlib for wxPython
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title=title,
size=(350, 250))
# Initialize the Matplotlib graph
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self, -1, self.figure)
# Create a timer for redrawing the frame every 100 milliseconds
self.Timer = wx.Timer(self)
self.Timer.Start(100)
self.Bind(wx.EVT_TIMER, self.OnPaint)
# Show the frame
self.Centre()
self.Show()
def OnPaint(self, event=None):
# Get data from serial port
value = arduino.readline()
# Draw the serial data
# Cleare the previos graph
self.axes.clear()
# Set the Y axis limit in order to provide consistency in the visualization
self.axes.set_ylim([0,100])
# Draw the bar
self.axes.bar(1,value)
# Update the graph
self.canvas.draw()
# Main program
if __name__ == '__main__':
# Connect to serial port first
try:
arduino = serial.Serial('/dev/tty.usbmodem1421', 9600)
except:
print "Failed to connect"
exit()
# Create and launch the wx interface
app = wx.App()
MyFrame(None, 'Serial data test')
app.MainLoop()
# Close the serial connection
arduino.close()