So recently I decided to take a serious attempt at programming with using a GUI. While it has not been easy, the results are very satisfying. This program was entirely from scratch to get my feet wet, but I think my next project will be converting an already existing program to a GUI.
I chose wx over Tkinter for a couple reasons. The first was wx looks native while Tkinter looks like a Java application. Also, much like a Java application, however the windows are made with Tkinter, they have a bad habit of glitching out and making pieces illegible. The downside to wx is that it is not included with Python, however the wx packages are easy enough to get a hold of (in many different languages) and easy to install.
I'm happy with the end result, both the GUI and the code. I spent some extra time afterwards cleaning up the code, expanding variable names and commenting. This proved useful since I deleted a bunch of code that didn't do anything. Granted it's not perfect, I'm happy that overall it works.
You can check it out on my site
here, or just copy/paste the source code.
#!/usr/bin/env python
# Author: Matthew DeSantis
#
# Resistor Calc
import wx
# Colors aranged by value (index=value)
COLOR = [
'black',
'brown',
'red',
'orange',
'yellow',
'green',
'blue',
'violet',
'grey',
'white']
# Colors because the default ones suck
COLORCODE = {
"black": "#000000",
"brown": "#a52a2a",
"red": "#ff0000",
"orange": "#ffa500",
"yellow": "#ffff00",
"green": "#008000",
"blue": "#0000ff",
"violet": "#800080",
"grey": "#808080",
"white": "#ffffff",
"silver": "#c0c0c0",
"gold": "#d4a017"}
# Multipliers in a dictionary, organized by value for ease of reading
MULTIPLIER = {
1e-2: 'silver',
1e-1: 'gold',
1e0: 'black',
1e1: 'brown',
1e2: 'red',
1e3: 'orange',
1e4: 'yellow',
1e5: 'green',
1e6: 'blue',
1e7: 'violet',}
# Converts a number to a list of resistor colors of equivalent value
def getColors(num):
# To-be return value
returnVals = []
failReturnVals = [COLOR[0], COLOR[0], MULTIPLIER[1e0]]
# Process the number
indexPlaceholder = 0
numStr = str(num)
bandValues = ""
# For anything smaller than 0
if num < 1 and num >= 0.01:
while indexPlaceholder < len(numStr):
# Discard leading 0's and decimal
if numStr[indexPlaceholder] == "0" or numStr[indexPlaceholder] == ".":
indexPlaceholder += 1
else:
break
# It's all zeroes, time to leave
else:
return failReturnVals
bandValues = numStr[indexPlaceholder:]
# Short a value, needs a black band
if len(bandValues) < 2:
bandValues = bandValues + "0"
# Ready return color values
before = True
for value in bandValues:
if len(returnVals) < 2:
returnVals.append(COLOR[int(value)])
elif value != "0":
ret.append(COLOR[int(value)])
else:
break
# And everything else
elif num >= 1 and num <= 9990000000:
indexPlaceholder = 2
bandValues = numStr[:indexPlaceholder]
# If there's 4 stripes
if (num / float(bandValues)) % 10:
indexPlaceholder = 3
bandValues = numStr[:indexPlaceholder]
# If there's a third band to add
if len(numStr) > indexPlaceholder:
if numStr[indexPlaceholder] != "0":
bandValues = numStr[:indexPlaceholder + 1]
# Needs another black band
if len(bandValues) < 2:
bandValues = bandValues + "0"
for value in bandValues:
if value == ".":
continue
returnVals.append(COLOR[int(value)])
# Outside the limit
else:
return failReturnVals
# Get the multiplier
returnVals.append(MULTIPLIER[round(num / float(bandValues.replace(".", "")), 2)])
return returnVals
#List of colors to Ohms
def getOhms(colors):
bandValues = ""
# Key storage
multiply = 0
# Get the index numbers of the colors
while len(colors) > 1:
bandValues = bandValues + str(COLOR.index(colors.pop(0)))
# Find the key (multiplier) based on color (no easy way to do this)
for key, value in MULTIPLIER.items():
if value == colors[0]:
multiply = key
break
# Color value * multiplier
return float(bandValues) * multiply
def main():
# Initialize app
app = wx.App()
frame = Window(None, "Resistor Calc")
frame.display()
app.MainLoop()
# The GUI class setup
class Window(wx.Frame):
def __init__(self, parent, title):
# Initialize the frame
super(Window, self).__init__(
parent,
title=title,
style=wx.DEFAULT_FRAME_STYLE,
size=(550, 200))
# UI setup
self.uiInit()
self.evtInit()
self.colorSet()
# Control variables
self.lock = False
self.prvs = self.ohmstxt.GetValue()
def uiInit(self):
# Third band list (needs optional added)
self.r3colors = COLOR[:]
self.r3colors.insert(0, "-")
# Fourth band has some extra as well (organize by values)
self.r4colors = COLOR[:-2]
self.r4colors.insert(0, "gold")
self.r4colors.insert(0, "silver")
# Create panel and sub panels for colored boxes
self.panel = wx.Panel(self)
self.pr1 = wx.Panel(self.panel)
self.pr2 = wx.Panel(self.panel)
self.pr3 = wx.Panel(self.panel)
self.pr4 = wx.Panel(self.panel)
# Initialize font
font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
font.SetPointSize(12)
# Boxes for resizing and aligning
# 3 tall
self.vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
# First row
lblohms = wx.StaticText(self.panel, label="Ohms:")
lblohms.SetFont(font)
self.ohmstxt = wx.TextCtrl(self.panel, value="0.0")
# Second row
lblcolor = wx.StaticText(self.panel, label="Colors:")
lblcolor.SetFont(font)
self.r1 = wx.ComboBox(
self.panel,
choices=COLOR,
style=wx.CB_READONLY)
self.r2 = wx.ComboBox(
self.panel,
choices=COLOR,
style=wx.CB_READONLY)
self.r3 = wx.ComboBox(
self.panel,
choices=self.r3colors,
style=wx.CB_READONLY)
self.r4 = wx.ComboBox(
self.panel,
choices=self.r4colors,
style=wx.CB_READONLY)
# Create first row
hbox1.Add(lblohms, flag=wx.RIGHT, border=8)
hbox1.Add(self.ohmstxt, proportion=1)
# Create second row
hbox2.AddMany([
(lblcolor, wx.RIGHT, 8),
(self.r1,),
(self.r2,),
(self.r3,),
(self.r4,)])
# Create third row
hbox3.AddMany([
(self.pr1, 1, wx.EXPAND),
(self.pr2, 1, wx.EXPAND),
(self.pr3, 1, wx.EXPAND),
(self.pr4, 1, wx.EXPAND)])
# Insert rows with padding
self.vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
self.vbox.Add((-1, 10))
self.vbox.Add(hbox2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=10)
self.vbox.Add((-1, 10))
self.vbox.Add(hbox3, 1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=10)
self.vbox.Add((-1, 10))
# Sets everything in place on the window
self.panel.SetSizer(self.vbox)
# Set combobox selections (not intialized by default
self.r1.SetSelection(0)
self.r2.SetSelection(0)
self.r3.SetSelection(0)
self.r4.SetSelection(2)
# Initialize events
def evtInit(self):
self.Bind(wx.EVT_COMBOBOX, self.onCBChange)
self.Bind(wx.EVT_TEXT, self.onTextChange)
# Combobox was changed
def onCBChange(self, e):
self.lock = True
bandColors = []
thirdBand = self.r3.GetValue()
bandColors.append(self.r1.GetValue())
bandColors.append(self.r2.GetValue())
# Third band is optional, check to see if it's actually used
if thirdBand != "-":
bandColors.append(thirdBand)
bandColors.append(self.r4.GetValue())
self.ohmstxt.SetValue(str(getOhms(bandColors)))
self.colorSet()
# Text change
def onTextChange(self, e):
ohms = self.ohmstxt.GetValue()
# This is because event fires twice for some unknown reason
if self.lock or ohms == self.prvs:
self.prvs = ohms
self.lock = False
return None
# If no value given, default to zero
if not ohms:
ohms = "0"
try:
bandColors = getColors(float(ohms))
self.r1.SetSelection(COLOR.index(bandColors[0]))
self.r2.SetSelection(COLOR.index(bandColors[1]))
# All 4 bands are present
if len(bandColors) > 3:
self.r3.SetSelection(self.r3colors.index(bandColors[2]))
self.r4.SetSelection(self.r4colors.index(bandColors[3]))
# Third band is not present
else:
self.r3.SetSelection(0)
self.r4.SetSelection(self.r4colors.index(bandColors[2]))
self.colorSet()
# Not a valid number or possible value
except (ValueError, KeyError):
pass
# Display the colors for the bands
def colorSet(self):
self.pr1.SetBackgroundColour(COLORCODE[self.r1.GetValue()])
self.pr2.SetBackgroundColour(COLORCODE[self.r2.GetValue()])
# If band 3 isn't used, don't show it
if self.r3.GetValue() == "-":
self.pr3.SetBackgroundColour(wx.NullColour)
else:
self.pr3.SetBackgroundColour(COLORCODE[self.r3.GetValue()])
self.pr4.SetBackgroundColour(COLORCODE[self.r4.GetValue()])
def display(self):
self.Centre
self.Show()
if __name__ == '__main__':
main()