-
Notifications
You must be signed in to change notification settings - Fork 0
/
calculator.py
146 lines (125 loc) · 4.97 KB
/
calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
###Known bug when % or / by 0
import tkinter as tk
HEIGHT = 280
WIDTH = int((HEIGHT/4)*3) #width is always 3/4 height
DISPLHEIGHT = int(HEIGHT/4) #display takes 1/4 height
BTNHEIGHT = 2 ########################
BTNWIDTH = 6 #########################
window = tk.Tk()
window.title("Calculator")
window.geometry("%dx%d" % (WIDTH, HEIGHT))
window.resizable(0, 0) #prevent resizing
displStr = tk.StringVar()
displStr.set("0") #start the calculator empty
current = 0 #the number displayed
previous = 0 #the number before operation started
operator = "0" #"0" is unset
decNo = 0 #the number decimal place
#the calculator's display or output
frDispl = tk.Frame(window, width=WIDTH, height=DISPLHEIGHT, background="grey")
frDispl.pack()
frDispl.pack_propagate(0) #stops widgets messing with their parents config
lblDispl = tk.Label(frDispl, textvariable=displStr)
lblDispl.pack(side="right")
#a separate frame just for the buttons
frButtons = tk.Frame(window, width=WIDTH, height=HEIGHT-DISPLHEIGHT)
frButtons.pack()
frButtons.pack_propagate(0) #stops widgets messing with their parents config
#funbuttons slightly different properties so have to assign separately
bDiv = tk.Button(frButtons, text="/", command = lambda : numPress("/"))
bMod = tk.Button(frButtons, text="%", command = lambda : numPress("%"))
bNeg = tk.Button(frButtons, text="-X", command = lambda : numPress("-X"))
bC = tk.Button(frButtons, text="C", command = lambda : numPress("C"))
bMult = tk.Button(frButtons, text="*", command = lambda : numPress("*"))
bSub = tk.Button(frButtons, text="-", command = lambda : numPress("-"))
bAdd = tk.Button(frButtons, text="+", command = lambda : numPress("+"))
bEq = tk.Button(frButtons, text="=", command = lambda : numPress("="))
bDec = tk.Button(frButtons, text=".", command = lambda : numPress("."))
#list of buttons to allow batch configs
funcButtons = [bDiv, bMod, bNeg, bC, bMult, bSub, bAdd, bEq, bDec]
for btn in funcButtons: #batch config function buttons
btn.config(height=BTNHEIGHT, width=BTNWIDTH)
#place function buttons in their appropriate position
bDiv.grid(row=0, column=3)
bMod.grid(row=0, column=2)
bNeg.grid(row=0, column=1)
bC.grid(row=0, column=0)
bMult.grid(row=1, column=3)
bSub.grid(row=2, column=3)
bAdd.grid(row=3, column=3)
bEq.grid(row=4, column=3)
bDec.grid(row=4, column=2)
#create and place number buttons
for i in range(9, -1, -1): #last number (-1) is loop increment
btn = tk.Button(frButtons)
btn.config(text="%d" % (i), command = lambda i=i: numPress(i), \
height=BTNHEIGHT, width=BTNWIDTH)
if i == 0:
#0 on row 4
btn.grid(row=4)
elif i <= 3:
#1-3 on row 3
btn.grid(row=3, column=(i+2)%3)
elif i <= 6:
#4-6 on row 2
btn.grid(row=2, column=(i+2)%3)
elif i <= 9:
#7-9 on row 1
btn.grid(row=1, column=(i+2)%3)
#function for any calculator button clicked, each passes its ID
def numPress(clicked):
global displStr
global current #the number displayed
global previous #the number before operation started
global operator #"0" is unset
global decNo #the number decimal place
calculation = [previous, current, operator]
print(calculation)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if clicked in numbers: #user clicked a number
if current == 0 or current == previous:
current = clicked
elif decNo > 0:
current += (clicked / (10**decNo)) #add digits in the decimals
current = round(current, decNo) #round to the current decimal place
decNo += 1
else:
current *= 10 #move up a tenth place
current += clicked
elif clicked == "C": #clear
current = 0
operator = "0"
decNo = 0
elif clicked == "-X": #negative
if current != previous: #ensure a negative can't happen mid operation
current *= -1
elif clicked == ".": #decimal
decNo += 1
elif clicked == "=": #equals
current = evaluate(calculation)
operator = "0"
decNo = 0
else: #one of the 5 operations
if operator != "0": #evaluate then set up next operation
current = evaluate(calculation)
operator = clicked
else: #first operation
previous = current
operator = clicked
return #so that the display isn't updated
if current % 1 == 0: #if current is a whole number
current = int(current) #ensure it's an int so e.g. 5.0 isn't displayed
displStr.set(current)
#function to evaluate a statement given two numbers and an operator
def evaluate(calculation):
if calculation[2] == "+":
return calculation[0] + calculation[1]
elif calculation[2] == "-":
return calculation[0] - calculation[1]
elif calculation[2] == "*":
return calculation[0] * calculation[1]
elif calculation[2] == "/":
return calculation[0] / calculation[1]
elif calculation[2] == "%":
return calculation[0] % calculation[1]
window.mainloop()