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.
A GCode-STL viewer in Python (wxPython for the GUI and PyOpenGl for the 3D visualization): https://github.com/dkobozev/tatlin
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()
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() |
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() |