Now for the events. We need to catch the events thrown by our buttons. This will require a modification of our button loop, as well as some work for our clear button. It would also be wise to set a maximum length for our dislay:
from wxPython.wx import *
class CalculatorFrame ( wxFrame ):
def __init__ ( self ):
wxFrame.__init__ ( self, None, -1, 'PyCalc' )
self.panel = wxPanel ( self, -1 )
self.sizer = wxGridBagSizer ( 1, 1 )
self.display = wxTextCtrl ( self.panel, -1, '0.', style = wxTE_READONLY | wxTE_RIGHT )
# Add a maximum length
self.display.SetMaxLength ( 5 )
self.sizer.Add ( self.display, ( 0, 0 ), ( 1, 5 ), wxEXPAND )
self.memoryDisplay = wxStaticText ( self.panel, -1, '0', style = wxALIGN_CENTER )
self.sizer.Add ( self.memoryDisplay, ( 4, 0 ), ( 1, 1 ), wxALIGN_CENTER )
self.sizer.Add ( wxButton ( self.panel, 107, 'Clear', size = ( 30, 30 ) ), ( 5, 0 ), ( 1, 2 ), wxEXPAND )
# Catch the event thrown by our clear button
EVT_BUTTON ( self.panel, 107, self.handler )
buttons = [ [ None, None, None, None, None ], \
[ [ 'M+', 100 ], [ '1', 1 ], [ '2', 2 ], [ '3', 3 ], [ '+', 200 ] ], \
[ [ 'M-', 101 ], [ '4', 4 ], [ '5', 5 ], [ '6', 6 ], [ '-', 201 ] ], \
[ [ 'MR', 102 ], [ '7', 7 ], [ '8', 8 ], [ '9', 9 ], [ '*', 202 ] ], \
[ None, [ '.', 103 ], [ '0', 0 ], [ '=', 104 ], [ '/', 203 ] ], \
[ None, None, [ 'B', 105 ], [ '+/-', 106 ], [ 'sqrt', 204 ] ] ]
x = y = 0
for row in buttons:
for button in row:
if button == None:
x = x + 1
continue
self.sizer.Add ( wxButton ( self.panel, button [ 1 ], button [ 0 ], size = ( 30, 30 ) ), ( y, x ) )
# Catch the events thrown by our buttons
EVT_BUTTON ( self.panel, button [ 1 ], self.handler )
x = x + 1
x = 0
y = y + 1
self.panel.SetSizerAndFit ( self.sizer )
self.SetClientSize ( self.panel.GetSize() )
self.Show ( True )
calculator = wxPySimpleApp()
CalculatorFrame()
calculator.MainLoop()
Brace yourself. We're about to take a giant leap here. The first change we'll make is that we'll import the math module, needed for square roots. The second change will be to create some variables necessary to perform operations. Finally, we'll add the code required to perform operations:
from wxPython.wx import *
import math
class CalculatorFrame ( wxFrame ):
def __init__ ( self ):
wxFrame.__init__ ( self, None, -1, 'PyCalc' )
self.panel = wxPanel ( self, -1 )
self.sizer = wxGridBagSizer ( 1, 1 )
self.display = wxTextCtrl ( self.panel, -1, '0.', style = wxTE_READONLY | wxTE_RIGHT )
self.display.SetMaxLength ( 5 )
self.sizer.Add ( self.display, ( 0, 0 ), ( 1, 5 ), wxEXPAND )
self.memoryDisplay = wxStaticText ( self.panel, -1, '0', style = wxALIGN_CENTER )
self.sizer.Add ( self.memoryDisplay, ( 4, 0 ), ( 1, 1 ), wxALIGN_CENTER )
self.sizer.Add ( wxButton ( self.panel, 107, 'Clear', size = ( 30, 30 ) ), ( 5, 0 ), ( 1, 2 ), wxEXPAND )
EVT_BUTTON ( self.panel, 107, self.handler )
buttons = [ [ None, None, None, None, None ], \
[ [ 'M+', 100 ], [ '1', 1 ], [ '2', 2 ], [ '3', 3 ], [ '+', 200 ] ], \
[ [ 'M-', 101 ], [ '4', 4 ], [ '5', 5 ], [ '6', 6 ], [ '-', 201 ] ], \
[ [ 'MR', 102 ], [ '7', 7 ], [ '8', 8 ], [ '9', 9 ], [ '*', 202 ] ], \
[ None, [ '.', 103 ], [ '0', 0 ], [ '=', 104 ], [ '/', 203 ] ], \
[ None, None, [ 'B', 105 ], [ '+/-', 106 ], [ 'sqrt', 204 ] ] ]
x = y = 0
for row in buttons:
for button in row:
if button == None:
x = x + 1
continue
self.sizer.Add ( wxButton ( self.panel, button [ 1 ], button [ 0 ], size = ( 30, 30 ) ), ( y, x ) )
EVT_BUTTON ( self.panel, button [ 1 ], self.handler )
x = x + 1
x = 0
y = y + 1
# Add a variables for memory, last display and operation
self.memory = 0
self.last = None
self.operation = None
self.panel.SetSizerAndFit ( self.sizer )
self.SetClientSize ( self.panel.GetSize() )
self.Show ( True )
def handler ( self, event ):
# Retrieve the event's ID number
id = event.GetId()
# If the event ID corresponds to a number button, append the number
# If there is a leading zero, we'll get rid of it
if ( id >= 0 ) & ( id <= 9 ):
if self.display.GetValue() == '0.':
self.display.SetValue ( '' )
self.display.AppendText ( str ( id ) )
# Add to memory
elif id == 100:
self.memory = float ( self.display.GetValue() )
# Clear memory
elif id == 101:
self.memory = 0
# Recall memory if there's anything to recall
elif id == 102:
if self.memory != 0:
self.display.SetValue ( str ( self.memory ) )
# Add a decimal, if there is not already one
elif id == 103:
if self.display.GetValue().find ( '.' ) == -1:
self.display.AppendText ( '.' )
# Solve
elif id == 104:
self.solve()
# Backspace, if we can
elif id == 105:
if len ( self.display.GetValue() ) > 1:
self.display.SetValue ( self.display.GetValue() [ :-1 ] )
elif len ( self.display.GetValue() ) == 1:
self.display.SetValue ( '0.' )
# Make the number negative or positive by multiplying it by -1
elif id == 106:
self.display.SetValue ( str ( float ( self.display.GetValue() ) * -1 ) )
# Clear
elif id == 107:
self.display.SetValue ( '0.' )
self.last = None
self.operation = None
# Addition: put the current display in self.last and put "+" in self.operation
# Solve if necessary
elif id == 200:
self.solve()
self.last = self.display.GetValue()
self.operation = '+'
self.display.SetValue ( '0.' )
# Subtraction, similar to addition
elif id == 201:
self.solve()
self.last = self.display.GetValue()
self.operation = '-'
self.display.SetValue ( '0.' )
# Multiplication
elif id == 202:
self.solve()
self.last = self.display.GetValue()
self.operation = '*'
self.display.SetValue ( '0.' )
# Division
elif id == 203:
self.solve()
self.last = self.display.GetValue()
self.operation = '/'
self.display.SetValue ( '0.' )
# Square root
elif id == 204:
if float ( self.display.GetValue() ) > 0:
self.display.SetValue ( str ( math.sqrt ( float ( self.display.GetValue() ) ) ) )
def solve ( self ):
if ( self.last != None ) & ( self.operation != None ):
self.display.SetValue ( str ( eval ( str ( self.last ) + self.operation + str ( self.display.GetValue() ) ) ) )
self.last = None
self.operation = None
calculator = wxPySimpleApp()
CalculatorFrame()
calculator.MainLoop()
It seems like a lot, but it's not that complicated upon closer examination. The handler method checks to see what the event ID is equal to. Notice how the ID numbers correspond to the appropriate buttons. It then performs the required operation, manipulating the display and three variables: memory, last and operation. The memory variable contains the number currently in memory. The last variable contains the previous number in the display. The operation variable contains the current operation.
Evaluating that will, of course, produce 5.