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.
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()
No comments:
Post a Comment