Here little debugged version of my calculator posted earlier in GUI calculator thread. I prepared it after listening that their teacher did more limited calculator in around 150 lines of code with their graphics module.

This is 115 lines without empty lines and comment lines

``````>>> li=[i for i in open('SimplistiCalc.pyw')
... if i.strip() and not i.strip().startswith('#')]
>>> len(li)
115
>>>``````

Save attached gifs to same directory as the code.

Edited by pyTony

Attachments
``````## simple calculator inspired by GUI calculator thread, but using Tkinter

## solve division problems
from __future__ import division
from Tkinter import *
from math import *
from random import random

hyps=arc=''
mem=0
resflag=False ## for clearing the display after result automatically without CE

fact=factorial

def click_feedback():
pass

def ev(s):
if '__' in s: return 'Safety Error'
## try to fix bracket unbalance 'sin(pi' for example
brackc = s.count('(') - s.count(')')
try:    return eval((s + ')' * brackc).replace(',','.')) ## decimal point not comma
except: return 'Error'

def endswithint(s):
return not s.rstrip('0123456789').endswith('.')

## old solution for division not giving 1/3=0
## if you are using elder Python version than version 2.6
## also uncomment the line marked **** ('/' key)
##
##def endswithint(s):
##    return not s.rstrip('0123456789').endswith('.')
##
##    """ returns '.' if s ends with integer, nothing if it endswith float """
##    if endswithint(s): return '.'
##    return ""
##
def calc(s):
global resflag
display.set(ev(display.get()))
number.icursor('end')
resflag=True

def push_key(e):
global resflag
if display.get()=='Error': clear(e)
if 38 <= e.x < 38 + 5 * 32 and 110 <= e.y < 110 + 4 * 31:
x,y = ((e.x - 38) // 32, (e.y - 110) // 31)
key=keys[y][x]
if isinstance(key,basestring):
if resflag and display.get() and key in '0123456789':
clear(e)
resflag=False

## ****
##            if key=='/':

number.insert('insert',key)
##            number.icursor('end')
else:
key(e)
click_feedback()

if 34 <= e.x < 34 + 28 * 6 and 28 <= e.y < 24 * 3 + 28:
x,y = ((e.x - 34) // 28, (e.y - 28) // 24)
fkey=fkeys[y][x]
if isinstance(fkey,basestring):
if fkey in ('sin','cos','tan'):
display.set(hyp(fkey)+display.get())
else:
if (fkey[:2] in ['**','pi','fa']) or(fkey[0] in '()'):
number.insert('insert',fkey)
else:   display.set(fkey+display.get())
number.icursor('end')
else: fkey(e)
resflag=False

click_feedback()

def clear(e): display.set('')

def ac(e):
global mem
clear(e)
mem=0

def mp(e):
global mem
calc(e)
mem=mem+float(display.get())

def Min(e):
global mem
calc(e)
mem=float(display.get())

def MR(e):
global mem
if display.get() and display.get()[-1] in '0123456789':
display.set(str(mem))
else:
display.set(display.get()+str(mem))
number.icursor('end')

def ln(x): return log(x,e)

def hyptoggle(e):
global hyps
if hyps:    hyps = ''
else:       hyps = 'h'

def shifttoggle(e):
global arc,fkeys
if arc:
arc =  ''
panel1.config(image=image1)
fkeys=bfkeys
else:
arc = 'a'
panel1.config(image=image2)
fkeys=afkeys

def hyp(trig): return arc+trig+hyps+'('

def sign(e):
display.set('-'+display.get())
calc(e)

def bs(e):
if display.get(): display.set(display.get()[:-1])

def xtox(e): display.set(str(display.get())+'**'+str(display.get()))

bfkeys=(('1./(','**0.5','**2','log10(','ln(','**'),
(shifttoggle,'pi',hyptoggle,'sin','cos','tan'),
(sign, bs, '(',')',Min,MR))

afkeys=(('fact(','sqrt(',xtox,'10**','e**','**(1./'),
(shifttoggle,'random()',hyptoggle,'sin','cos','tan'), ## sin,cos,tan by function
(sign, bs, '(',')',Min,MR))

fkeys=bfkeys

keys=(('7','8','9',clear,ac),
('4','5','6','*','/'),
('1','2','3','+','-'),
('0','.','e',calc,mp))

root=Tk()
root.protocol("WM_DELETE_WINDOW",root.destroy)
display = StringVar()
number=Entry(root,textvariable=display, justify='center')
number.pack(side='top', fill='x', expand='no')
image1 = PhotoImage(file="calc.gif")
image2 = PhotoImage(file="calc2.gif")
w,h = image1.width(), image1.height()
root.title('SimplistiCalc')
root.geometry ="%dx%d+0+0" % (w, h)
panel1 = Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')
number.focus()
number.bind('<Return>',calc)
number.bind('<Escape>',clear)
root.bind('<Button-1>',push_key)
root.wait_window()``````

Specialties:
IT/Science/Contracts/Religious translation/interpreting FIN-ENG-FIN
Python programming

3
Contributors
9
Replies
35
Views
7 Years
Discussion Span
Last Post by fonzali

line 29 comment missing `.. if you are using elder Python version than version 2.6`

Now it works, nice concept!

It is quite easy to adapt to your own style by changing the pictures.

What little irritates me is the simulation of normal calculators 'hidden reverse calculation' like:
2*pi=sin

Maybe better to write version with global _ with last result (the ev passes single underscore) and take out all special conditions to add function to left instead of right.

Writing sin(1)+cos(3) requires now to push Min after sin:
1 sin Min CE 3 cos + MR = (OK, Min does not handle resflag properly OK. Lets move reset inside if)

Memory active indicator or (hyp key indicator) is also missing because of I just did not come around to implement it (I did for that GUI thread with that other guys calculator, one letter box with letter or not letter)

hyp key is only active until next function selection in normal calculator. Here it is until reselected. Just change like this if you want reseting hyp key after trig function press.

here is also change for Min to use resflag (resflag=False moved):

``````if 34 <= e.x < 34 + 28 * 6 and 28 <= e.y < 24 * 3 + 28:
x,y = ((e.x - 34) // 28, (e.y - 28) // 24)
fkey=fkeys[y][x]
if isinstance(fkey,basestring):
if fkey in ('sin','cos','tan'):
display.set(hyp(fkey)+display.get())
if hyps: hyptoggle(e)
else:
if (fkey[:2] in ['**','pi','fa']) or(fkey[0] in '()'):
number.insert('insert',fkey)
else:   display.set(fkey+display.get())
number.icursor('end')
resflag=False
else:
fkey(e)

click_feedback()``````

Then there is the click_feedback() to be implemented, optional sounds or visual effect from key push...

Edited by pyTony

Here still another Zip package with functions being inserted at cursor position like typing (simpler) and _ key instead of 1/x (use Home 1/ Enter from keyboard for that) to take last result multiple times in one formula. The result clearing is also removed. Length without comments and empty lines 110 lines.

``````## simple calculator inspired by GUI calculator thread, but using Tkinter

## solve division problems
from __future__ import division
from Tkinter import *
from math import *
from random import random

hyps=arc=''
mem=0
_ = 0 ## for keeping last result in memory
fact=factorial

def click_feedback():
pass

def ev(s):
if '__' in s: return 'Safety Error'
## try to fix bracket unbalance 'sin(pi' for example
brackc = s.count('(') - s.count(')')
try:    return eval(s + ')' * brackc)
except: return 'Error'

## old solution for division not giving 1/3=0
## enable instead of __future__ if you use Python < 2.6
## also uncomment the line marked **** ('/' key)
##
##def endswithint(s):
##    return not s.rstrip('0123456789').endswith('.')
##
##    """ returns '.' if s ends with integer, nothing if it endswith float """
##    if endswithint(s): return '.'
##    return ""
##
def calc(s):
global _
_ = ev(display.get())
display.set(_)
number.icursor('end')

def push_key(e):
if display.get()=='Error' : clear(e)
if 38 <= e.x < 38 + 5 * 32 and 110 <= e.y < 110 + 4 * 31:
x,y = ((e.x - 38) // 32, (e.y - 110) // 31)
key=keys[y][x]
if isinstance(key,basestring):
## ****
##            if key=='/':

number.insert('insert',key)
else: key(e)
click_feedback()

if 34 <= e.x < 34 + 28 * 6 and 28 <= e.y < 24 * 3 + 28:
x,y = ((e.x - 34) // 28, (e.y - 28) // 24)
fkey=fkeys[y][x]
if isinstance(fkey,basestring):
if fkey in ('sin','cos','tan'):
fkey=hyp(fkey)
if hyps: hyptoggle(e)
number.insert('insert',fkey)
else:
fkey(e)

click_feedback()

def clear(e): display.set('')

def ac(e):
global mem
clear(e)
mem=0

def mp(e):
global mem
calc(e)
mem=mem+float(display.get())

def Min(e):
global mem
calc(e)
mem=float(display.get())

def MR(e):
global mem
if display.get() and display.get()[-1] in '0123456789':
display.set(str(mem))
else:
display.set(display.get()+str(mem))
number.icursor('end')

def ln(x): return log(x,e)

def hyptoggle(e):
global hyps
if hyps:    hyps = ''
else:       hyps = 'h'

def shifttoggle(e):
global arc,fkeys
if arc:
arc =  ''
panel1.config(image=image1)
fkeys=bfkeys
else:
arc = 'a'
panel1.config(image=image2)
fkeys=afkeys

def hyp(trig): return arc+trig+hyps+'('

def sign(e):
display.set('-'+display.get())
calc(e)

def bs(e):
if display.get(): display.set(display.get()[:-1])

def xtox(e): display.set(str(display.get())+'**'+str(display.get()))

bfkeys=(('_','**0.5','**2','log10(','ln(','**'),
(shifttoggle,'pi',hyptoggle,'sin','cos','tan'),
(sign, bs, '(',')',Min,MR))

afkeys=(('fact(','sqrt(',xtox,'10**','e**','**(1./'),
(shifttoggle,'random()',hyptoggle,'sin','cos','tan'), ## sin,cos,tan by function
(sign, bs, '(',')',Min,MR))

fkeys=bfkeys

keys=(('7','8','9',clear,ac),
('4','5','6','*','/'),
('1','2','3','+','-'),
('0','.','e',calc,mp))

root=Tk()
root.protocol("WM_DELETE_WINDOW",root.destroy)
display = StringVar()
number=Entry(root,textvariable=display, justify='center')
number.pack(side='top', fill='x', expand='no')
image1 = PhotoImage(file="calc3.gif")
image2 = PhotoImage(file="calc2.gif")
w,h = image1.width(), image1.height()
root.title('SimplistiCalc')
root.geometry ="%dx%d+0+0" % (w, h)
panel1 = Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')
number.focus()
number.bind('<Return>',calc)
number.bind('<Escape>',clear)
root.bind('<Button-1>',push_key)
root.wait_window()
``````

Fixed older version again:

``````## simple calculator inspired by GUI calculator thread, but using Tkinter
## original version fixed

## solve division problems
from __future__ import division
from Tkinter import *
from math import *
from random import random

hyps=arc=''
mem=0
resflag=False ## for clearing the display after result automatically without CE

fact=factorial

def click_feedback():
pass

def ev(s):
if '__' in s: return 'Safety Error'
## try to fix bracket unbalance 'sin(pi' for example
brackc = s.count('(') - s.count(')')
try:    return eval(s + ')' * brackc)
except: return 'Error'

## old solution for division not giving 1/3=0
## enable instead of __future__ if you use Python < 2.6
## also uncomment the line marked **** ('/' key)
##
##def endswithint(s):
##    return not s.rstrip('0123456789').endswith('.')
##
##    """ returns '.' if s ends with integer, nothing if it endswith float """
##    if endswithint(s): return '.'
##    return ""
##
def calc(s):
global resflag
display.set(ev(display.get()))
number.icursor('end')
resflag=True

def push_key(e):
global resflag
if display.get()=='Error': clear(e)
if 38 <= e.x < 38 + 5 * 32 and 110 <= e.y < 110 + 4 * 31:
x,y = ((e.x - 38) // 32, (e.y - 110) // 31)
key=keys[y][x]
if isinstance(key,basestring):
if resflag and display.get() and key in '0123456789':
clear(e)
resflag=False

## ****
##            if key=='/':

number.insert('insert',key)
##            number.icursor('end')
else:
key(e)
click_feedback()

if 34 <= e.x < 34 + 28 * 6 and 28 <= e.y < 24 * 3 + 28:
x,y = ((e.x - 34) // 28, (e.y - 28) // 24)
fkey=fkeys[y][x]
if isinstance(fkey,basestring):
if fkey in ('sin','cos','tan'):
display.set(hyp(fkey)+display.get())
if hyps: hyptoggle(e)
else:
if (fkey[:2] in ['**','pi','fa']) or(fkey[0] in '()'):
number.insert('insert',fkey)
else:   display.set(fkey+display.get())
number.icursor('end')
resflag=False
else:
fkey(e)

click_feedback()

def clear(e): display.set('')

def ac(e):
global mem
clear(e)
mem=0

def mp(e):
global mem
calc(e)
mem=mem+float(display.get())

def Min(e):
global mem
calc(e)
mem=float(display.get())

def MR(e):
global mem
if display.get() and display.get()[-1] in '0123456789':
display.set(str(mem))
else:
display.set(display.get()+str(mem))
number.icursor('end')

def ln(x): return log(x,e)

def hyptoggle(e):
global hyps
if hyps:    hyps = ''
else:       hyps = 'h'

def shifttoggle(e):
global arc,fkeys
if arc:
arc =  ''
panel1.config(image=image1)
fkeys=bfkeys
else:
arc = 'a'
panel1.config(image=image2)
fkeys=afkeys

def hyp(trig): return arc+trig+hyps+'('

def sign(e):
display.set('-'+display.get())
calc(e)

def bs(e):
if display.get(): display.set(display.get()[:-1])

def xtox(e): display.set(str(display.get())+'**'+str(display.get()))

bfkeys=(('1./(','**0.5','**2','log10(','ln(','**'),
(shifttoggle,'pi',hyptoggle,'sin','cos','tan'),
(sign, bs, '(',')',Min,MR))

afkeys=(('fact(','sqrt(',xtox,'10**','e**','**(1./'),
(shifttoggle,'random()',hyptoggle,'sin','cos','tan'), ## sin,cos,tan by function
(sign, bs, '(',')',Min,MR))

fkeys=bfkeys

keys=(('7','8','9',clear,ac),
('4','5','6','*','/'),
('1','2','3','+','-'),
('0','.','e',calc,mp))

root=Tk()
root.protocol("WM_DELETE_WINDOW",root.destroy)
display = StringVar()
number=Entry(root,textvariable=display, justify='center')
number.pack(side='top', fill='x', expand='no')
image1 = PhotoImage(file="calc.gif")
image2 = PhotoImage(file="calc2.gif")
w,h = image1.width(), image1.height()
root.title('SimplistiCalc')
root.geometry ="%dx%d+0+0" % (w, h)
panel1 = Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')
number.focus()
number.bind('<Return>',calc)
number.bind('<Escape>',clear)
root.bind('<Button-1>',push_key)
root.wait_window()
``````

Edited by pyTony: Inlined

Attachments

hi pytony , I appreciate if you explain to me how the keys in the image corespond to my keyboard keys , eg, if I click on button 3 on the image , 3 will appear , and ,this code is way over my head , more explanation on each def is greately appreciated thanks

By reducing margins and dividing by spacing:

``````x,y = ((e.x - 38) // 32, (e.y - 110) // 31)
``````

can you explain how you got those numbers?

By printing the values when moving the mouse to corners.

ok thanks

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.