Start New Discussion within our Software Development Community

Here is an example how to write a program to convert between units of distance, area, volume, weight, pressure, and energy. The wxPython GUI toolkit's wx.NoteBook() widget is used to make good use of the limited frame/window space available.

# a semi practical use of wxPython's wx.Notebook() widget
# converting ...
# distance, area, volume, weight, pressure, and energy units
# tested with Python25 and wxPython28 by vegaseat 11aug2008

import wx

class MyNotebook(wx.Frame):
    def __init__(self, parent, title, distD, areaD, volD,
            weightD, pressD, energyD):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title,
            size=(460, 360))

        # style=wx.NB_TOP is default
        # could use style=wx.NB_BOTTOM
        nb = wx.Notebook(self, wx.ID_ANY)
        # MyPage(parent, conversion dictionary, preselected choice)
        self.page1 = MyPage(nb, distD, 3)
        self.page2 = MyPage(nb, areaD, 2)
        self.page3 = MyPage(nb, volD, 0)
        self.page4 = MyPage(nb, weightD, 2)
        self.page5 = MyPage(nb, pressD, 2)
        self.page6 = MyPage(nb, energyD, 7)
        nb.AddPage(self.page1, "Distance")
        nb.AddPage(self.page2, "Area")
        nb.AddPage(self.page3, "Volume")
        nb.AddPage(self.page4, "Weight")
        nb.AddPage(self.page5, "Pressure")
        nb.AddPage(self.page6, "Energy")
        # start with page1 active
        self.page1.SetFocus()

class MyPage(wx.Panel):
    """
    each panel instance creates the notbook page content
    from the given conversion dictionary convD
    """
    def __init__(self, parent, convD, preselect):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        oatmeal3 = '#FCFFE1'
        self.SetBackgroundColour(oatmeal3)

        self.convD = convD

        # create list of possible units
        self.options = convD.keys()

        self.radiobox1 = wx.RadioBox(self, wx.ID_ANY,
            "Select a unit to convert from",
            choices=self.options, style=wx.VERTICAL)
        # set radio button 1 as selected (first button is 0)
        self.radiobox1.SetSelection(preselect)
        # bind mouse click to an action
        self.radiobox1.Bind(wx.EVT_RADIOBOX, self.onAction)

        self.radiobox2 = wx.RadioBox(self, wx.ID_ANY,
            "Select a unit to convert to  ",
            choices=self.options, style=wx.VERTICAL)
        # set radio button 1 as selected (first button is 0)
        self.radiobox2.SetSelection(preselect)
        # bind mouse click to an action
        self.radiobox2.Bind(wx.EVT_RADIOBOX, self.onAction)

        # additional widgets
        self.label1 = wx.StaticText(self, wx.ID_ANY, "" )
        self.label2 = wx.StaticText(self, wx.ID_ANY, "" )

        self.edit1 = wx.TextCtrl(self, wx.ID_ANY, value="1.0",
            size=(150, 20))
        # respond to enter key when focus is on edit1
        self.edit1.Bind(wx.EVT_TEXT_ENTER, self.onAction)
        self.edit2 = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(150, 20))

        self.button = wx.Button(self, wx.ID_ANY, label='Convert')
        self.button.Bind(wx.EVT_BUTTON, self.onAction)

        # use box sizers to layout the widgets
        # nest the 3 vertical sizers in the horizontal sizer later
        sizer_v1 = wx.BoxSizer(wx.VERTICAL)
        sizer_v2 = wx.BoxSizer(wx.VERTICAL)
        sizer_v3 = wx.BoxSizer(wx.VERTICAL)
        sizer_h = wx.BoxSizer(wx.HORIZONTAL)
        # add the widgets to the corresponding vertical sizer
        sizer_v1.Add(self.radiobox1, 0, flag=wx.ALL, border=10)
        sizer_v1.Add(self.label1, 0, wx.LEFT|wx.RIGHT|wx.TOP, 10)
        sizer_v1.Add(self.edit1, 0, wx.LEFT|wx.RIGHT, 10)
        # add a spacer to position the button lower ...
        sizer_v2.Add((0, 225), 0, wx.ALL, 10)
        sizer_v2.Add(self.button, 0, wx.ALL, 10)
        sizer_v3.Add(self.radiobox2, 0, wx.ALL, 10)
        sizer_v3.Add(self.label2, 0, wx.LEFT|wx.RIGHT|wx.TOP, 10)
        sizer_v3.Add(self.edit2, 0, wx.LEFT|wx.RIGHT, 10)
        # put the 3 vertical sizers into the horizontal sizer
        sizer_h.Add(sizer_v1, 0)
        sizer_h.Add(sizer_v2, 0)
        sizer_h.Add(sizer_v3, 0)
        # it's the horizontal sizer you have to set
        self.SetSizer(sizer_h)

        # show present selection
        self.onAction(None)

    def onAction(self, event):
        """show the selected choice"""
        index1 = self.radiobox1.GetSelection()
        unit1 = self.options[index1]
        #print unit1  # test
        s = "Enter a value (%s):" % unit1
        self.label1.SetLabel(s)
        # dito for radio box #2
        index2 = self.radiobox2.GetSelection()
        unit2 = self.options[index2]
        #print unit2  # test
        s = "Result (%s):" % unit2
        self.label2.SetLabel(s)

        value = float(self.edit1.GetValue())
        factor1 = self.convD[unit1]
        factor2 = self.convD[unit2]
        result = factor2 * value/factor1
        self.edit2.ChangeValue(str(result))


# these are the conversion dictionaries ...
# (note that units won't appear in that order)
distD ={}
# all scale factors are relative to the first unit below
distD['meter'] = 1.0
distD['micron'] = 1000000.0
distD['millimeter'] = 1000.0
distD['centimeter'] = 100.0
distD['kilometer'] = 0.001
distD['inch'] = 100.0/2.54
distD['foot'] = 100.0/30.48
distD['yard'] = 100.0/91.44
distD['mile'] = 0.001/1.609344
distD['rod'] = 1.0/5.029

areaD = {}
# all scale factors are relative to the first unit below
areaD['sq meter'] = 1.0
areaD['sq millimeter'] = 1000000.0
areaD['sq centimeter'] = 10000.0
areaD['sq kilometer']  = 0.000001
areaD['hectare'] = 0.0001
areaD['sq inch'] = 1550.003
areaD['sq foot'] = 10.76391
areaD['sq yard'] = 1.19599
areaD['acre'] = 0.0002471054
areaD['sq mile'] = 0.0000003861022

volD = {}
# all scale factors are relative to the first unit below
volD['cubic meter'] = 1.0
volD['microliter'] = 1000000000.0
volD['milliliter'] = 1000000.0
volD['liter'] = 1000.0
volD['pint(US)'] = 2113.376
volD['quart(US)'] = 1056.688
volD['gallon(US)'] = 264.172
volD['cubic inch'] = 61023.74
volD['cubic foot'] = 35.31467
volD['cubic yard'] = 1.307951

weightD = {}
# all scale factors are relative to the first unit below
weightD['kilogram'] = 1.0
weightD['microgram'] = 1000000000.0
weightD['milligram'] = 1000000.0
weightD['gram'] = 1000.0
weightD['tonne (metric)'] = 0.001
weightD['dram (avd)'] = 564.38339
weightD['grain'] = 15432.358
weightD['ounce (avd)'] = 35.273962
weightD['pound (avd)'] = 2.2046226
weightD['ton (short)'] = 0.0011023113

pressD = {}
# all scale factors are relative to the first unit below
pressD['atm'] = 1.0
pressD['bar'] = 1.01325
pressD['kilopascal'] = 101.325
pressD['torr'] = 760
pressD['kg/sqcm'] = 1.033227
pressD['kg/sqm'] = 10332.27
pressD['lb/sqinch'] = 14.69595
pressD['ton(sh)/sqfoot'] = 1.058108
pressD['inch of Hg'] = 29.92126
pressD['foot of water'] = 33.89854

energyD = {}
# all scale factors are relative to the first unit below
energyD['calorie'] = 1.0
energyD['kilocalorie'] = 0.001
energyD['joule or watt-second'] = 4.1868
energyD['watt-hour'] = 0.001163
energyD['kilowatt-hour'] = 0.000001163
energyD['liter-atmosphere'] = 0.0413205
energyD['horsepower-hour metric'] = 0.00000158124
energyD['erg'] = 4186800
energyD['btu'] = 0.00396832

app = wx.App(1)
mynotebook = MyNotebook(None, "Conversion Program", distD, areaD,
    volD, weightD, pressD, energyD)
mynotebook.Show()
app.MainLoop()
The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.