Ok so I'm supposed to make a basic calculator using GUI in python. I completed that task with all buttons working. Now for step 2, I'm supposed to inherit the original calculator class and create a new class called BetterCalculator, which adds in the buttons sqrt, log, pct, and pow. I have got everything working except for the pow button and when I run the program with what the teacher calls a driver, I get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "E:\calculator\Calculator in class\calculator.py", line 102, in do3
self.n.set(self.n.get()+'3')
TypeError: 'str' object is not callable
and here is my code:
#Windows basic built-in interface library.
import tkinter
import math
class Calculator:
def __init__(self):
self.win = tkinter.Tk() # Window object created
# Create frames for buttons. Win frame, topFrame(label, display) \
# bottomFrame (numberFrame
self.topFrame = tkinter.Frame(self.win)
self.bottomFrame = tkinter.Frame(self.win)
self.numbersFrame = tkinter.Frame(self.bottomFrame)
self.no123Frame = tkinter.Frame(self.numbersFrame)
self.no456Frame = tkinter.Frame(self.numbersFrame)
self.no789Frame = tkinter.Frame(self.numbersFrame)
self.no0DFrame = tkinter.Frame(self.numbersFrame)
self.optsFrame = tkinter.Frame(self.bottomFrame)
# Create object Label to use for input and output. StringVar is a class.
self.n = tkinter.StringVar()
# Display object created
self.display = tkinter.Label(self.topFrame, textvariable = self.n, bg = 'white', font = 12, height = 2, width = 20)
# Number Buttons created. self.b1 = object, tkinter.button calls button module, command = do1 will\
# become a method.
self.b1 = tkinter.Button(self.no123Frame, width = 3 , text = '1', command = self.do1)
self.b2 = tkinter.Button(self.no123Frame, width = 3 , text = '2', command = self.do2)
self.b3 = tkinter.Button(self.no123Frame, width = 3 , text = '3', command = self.do3)
self.b4 = tkinter.Button(self.no456Frame, width = 3 , text = '4', command = self.do4)
self.b5 = tkinter.Button(self.no456Frame, width = 3 , text = '5', command = self.do5)
self.b6 = tkinter.Button(self.no456Frame, width = 3 , text = '6', command = self.do6)
self.b7 = tkinter.Button(self.no789Frame, width = 3 , text = '7', command = self.do7)
self.b8 = tkinter.Button(self.no789Frame, width = 3 , text = '8', command = self.do8)
self.b9 = tkinter.Button(self.no789Frame, width = 3 , text = '9', command = self.do9)
self.b0 = tkinter.Button(self.no0DFrame, width = 3 , text = '0', command = self.do0)
self.bD = tkinter.Button(self.no0DFrame, width = 3 , text = '.', command = self.doD)
self.bCal = tkinter.Button(self.no0DFrame, width = 3 , text = '=', command = self.cal)
# Operators created
self.bAdd = tkinter.Button(self.optsFrame, width = 5, text = '+', command = self.add)
self.bSub = tkinter.Button(self.optsFrame, width = 5, text = '-', command = self.sub)
self.bMul = tkinter.Button(self.optsFrame, width = 5, text = '*', command = self.mul)
self.bDiv = tkinter.Button(self.optsFrame, width = 5, text = '/', command = self.div)
self.bMod = tkinter.Button(self.optsFrame, width = 5, text = '%', command = self.mod)
self.bClr = tkinter.Button(self.topFrame, width = 5, text = 'Clear', command = self.clr)
# Create numbers. op1 = operand, op2 = operator
op1 = 0.0
op2 = 0.0
opt = ''
def organizeInterface(self):
# Method pack object(assembling display label into window).
# Order of packing will be the order the labels will display.
self.display.pack(side = 'left')
self.bClr.pack()
self.topFrame.pack()
self.b1.pack(side = 'left')
self.b2.pack(side = 'left')
self.b3.pack(side = 'left')
self.no123Frame.pack()
self.b4.pack(side = 'left')
self.b5.pack(side = 'left')
self.b6.pack(side = 'left')
self.no456Frame.pack()
self.b7.pack(side = 'left')
self.b8.pack(side = 'left')
self.b9.pack(side = 'left')
self.no789Frame.pack()
self.bD.pack(side = 'left')
self.b0.pack(side = 'left')
self.bCal.pack(side = 'left')
self.no0DFrame.pack(side = 'left')
self.numbersFrame.pack(side = 'left')
self.bAdd.pack(side = 'left')
self.bSub.pack(side = 'left')
self.bDiv.pack(side = 'left')
self.bMul.pack(side = 'left')
self.bMod.pack(side = 'left')
self.optsFrame.pack()
self.bottomFrame.pack()
def runInterface(self):
tkinter.mainloop()
#clear user input.
def clear(self):
self.op1 = 0.0
self.op2 = 0.0
self.opt = ''
# Set user input, set variable self.n.set then self.n.get will append and concatonate.
def do1(self):
self.n.set(self.n.get()+'1')
def do2(self):
self.n.set(self.n.get()+'2')
def do3(self):
self.n.set(self.n.get()+'3')
def do4(self):
self.n.set(self.n.get()+'4')
def do5(self):
self.n.set(self.n.get()+'5')
def do6(self):
self.n.set(self.n.get()+'6')
def do7(self):
self.n.set(self.n.get()+'7')
def do8(self):
self.n.set(self.n.get()+'8')
def do9(self):
self.n.set(self.n.get()+'9')
def do0(self):
self.n.set(self.n.get()+'0')
def doD(self):
self.n.set(self.n.get()+'.')
# record operator = self.opt and get first number entry = self.n.get().
# need to clean up the label of the first number entry before getting next \
# entry of numbers.
def add(self):
self.opt = '+'
self.op1 = float(self.n.get())
self.n.set('')
#to get calculator to see negative number verse \
#subtraction create if statement for empty string.
def sub(self):
if self.n.get() == '':
self.n.set('-')
else:
self.opt = '-'
self.op1 = float(self.n.get())
self.n.set('')
def mul(self):
self.opt = '*'
self.op1 = float(self.n.get())
self.n.set('')
def div(self):
self.opt = '/'
self.op1 = float(self.n.get())
self.n.set('')
def mod(self):
self.opt = '%'
self.op1 = float(self.n.get())
self.n.set('')
# clear set to clr button to clean label
def clr(self):
self.clear()
self.n.set('')
# Call calculate method to get calculations and write if statements \
# to define what operator user wanted.
def cal(self):
self.op2 = float(self.n.get())
if self.opt == '+':
self.n.set(self.op1 + self.op2)
elif self.opt == '-':
self.n.set(self.op1 - self.op2)
elif self.opt == '*':
self.n.set(self.op1 * self.op2)
elif self.opt == '/':
self.n.set(self.op1 / self.op2)
elif self.opt == '%':
self.n.set(self.op1 % self.op2)
class BetterCalculator(Calculator):
def __init__(self):
Calculator.__init__(self)
self.uOptsFrame = tkinter.Frame(self.bottomFrame)
self.bLog = tkinter.Button(self.uOptsFrame, width = 5, text = 'log', command = self.log)
self.bPct = tkinter.Button(self.uOptsFrame, width = 5, text = 'Pct', command = self.pct)
self.bSqrt = tkinter.Button(self.uOptsFrame, width = 5, text = 'Sqrt', command = self.sqrt)
self.bPow = tkinter.Button(self.optsFrame, width = 5, text = 'pow', command = self.pow)
def reorganizeInterface(self):
self.bClr.configure(bg = 'red')
self.bAdd.configure(bg = 'yellow')
self.bSub.configure(bg = 'yellow')
self.bMul.configure(bg = 'yellow')
self.bDiv.configure(bg = 'yellow')
self.bMod.configure(bg = 'yellow')
self.bCal.configure(bg = 'green')
Calculator.organizeInterface(self)
self.bLog.pack()
self.bPct.pack()
self.bSqrt.pack()
self.bPow.pack()
self.uOptsFrame.pack(side='left')
def log(self):
self.op1 = float(self.n.get())
self.n.set(math.log(self.op1))
def pct(self):
self.op1 = float(self.n.get())
self.n.set(self.op1 * 100)
def sqrt(self):
self.op1 = float(self.n.get())
self.n.set(math.sqrt(self.op1))
def pow(self):
self.opt = 'pow'
self.op1 = float(self.n.get())
self.n.set = ('')
def cal(self):
Calculator.cal(self)
if self.opt == 'pow':
self.n.set(self.op1 ** self.op2)
this is a separate file for the driver of this program to make it run:
import calculator
import math
def main():
myCal = calculator.BetterCalculator()
myCal.reorganizeInterface()
myCal.runInterface()
main()
Without looking at the rest of the code, I see an obvious typo / brain-o in
pow
:That last line should be:
without the
=
part, so as to callself.n.set
, not to replace the function with a string. (Replacing the function with a string will cause a later attempt to callself.n.set
to produce the error you saw.)Look at your
pow()
methodIt's definitely is a typo. Replace with