Tuesday, January 11, 2022

IslandT: How to write a Python calculator interface program

In this article, let us write a Python calculator program with the help of the Tkinter module which comes together with the latest version of Python. This program will support any version of Python 3.

First of all this is how the calculator will look like after completion!

The interface of Simple Python Calculator

Now, let us continue with the concept of the calculator!

As you can see the above calculator is made out of numbers and various functional buttons such as the square root button which will calculate the square root of a number, for example, likes square root of 25 is 5! All functional buttons require you to touch the number first and then touch it later, for example, 2 (+) 3 (=) 5. With that in mind let us start to write the entire program in one single run. There are two files basically in this calculator package. 1) main.py is the main file where all the code which creates the calculator plus those functions that perform the various arithmetic operations will be written in this file! 2) calculate.py is the file that processes the remaining calculation for this calculator. Overall speaking, when you pressed a number and a functional button followed by another number and then press the equal button this calculator will present you with the answer!

Now let us create the user interface of the calculator and those functions that perform partial or all calculations! Tkinter will help us to create the user interface and each button will have a function attached to it.

# A calculator application

import tkinter as tk
import tkinter.font
from math import sqrt

from calculate import Calculate

win = tk.Tk()
win.title('Simple Calculator')
win.resizable(0,0)

data = Calculate()
operatorFlag = False #this flag control the operator operation
dataSet = []

memory = 0

total = []
total.append(0)
grandTotalFlag = False

def plusminus():
    if (entry.get() == "0"):
        pass
    else:
        dataSet.clear()
        dataSet.append(-float(entry.get()))
        entry.set(-float(entry.get()))

def clear(elem):
    if elem == "All":
        dataSet.clear()
        entry.set("0")
    else:
        if(len(dataSet) > 0):
            dataSet.pop(len(dataSet) - 1)
            entry.set(dataSet.pop(len(dataSet) - 1))

def insert(elem):
    global operatorFlag,total
    if operatorFlag == False and (len(dataSet)==0):
        dataSet.append(entry.get())
        dataSet.append(elem)
        operatorFlag = True
    elif operatorFlag == False and (len(dataSet)==1):
        dataSet.append(elem)
        operatorFlag = True
    elif operatorFlag == True and (len(dataSet)==0):
        dataSet.append(entry.get())
        dataSet.append(elem)
    elif len(dataSet) == 2:
        dataSet.append(entry.get())
        data.cal(dataSet,entry, total)

def insertNumber(elem):
    global operatorFlag
    if operatorFlag == False:
        if entry.get() == "0":
            entry.set(elem)
        elif len(dataSet) == 1:
            pass
        else:
            entry.set(entry.get()+elem)
    else:
        entry.set(elem)
        operatorFlag = False

def insertDot():
    if len(entry.get()) > 0 and "." not in entry.get():
        entry.set(entry.get() + ".")

def delete():
    if entry.get() == "0" or len(entry.get()) == 1:
        entry.set("0")
    else:
        entry.set(entry.get()[:len(entry.get()) - 1])

def percent():
    global operatorFlag
    pct = float(entry.get())/100
    entry.set(pct)
    dataSet.clear()
    dataSet.append(pct)

def otherOp(elem):

    global operatorFlag

    if operatorFlag == False:

        if elem == "1/x":
            if entry.get() == "0":
                entry.set(elem)
            else:
                entry.set(1/float(entry.get()))
        elif elem == "x\u00b2":
            if entry.get() == "0":
                entry.set(elem)
            else:
                entry.set((float(entry.get())**2))
        elif elem == "\u221Ax\u0305\u0305":
            if entry.get() == "0":
                entry.set(elem)
            else:
                entry.set((sqrt(float(entry.get()))))
        operatorFlag = True

    else:
        if elem == "1/x":
            entry.set(1/float(entry.get()))
        elif elem == "x\u00b2":
            entry.set((float(entry.get())**2))
        elif elem == "\u221Ax\u0305\u0305":
            entry.set((sqrt(float(entry.get()))))


def memClear():
    global memory
    memory = 0

def memRecall():
    global memory, operatorFlag
    entry.set(memory)
    operatorFlag = True

def memAdd():
    global memory
    memory += float(entry.get())

def memMinus():
    global memory
    memory -= float(entry.get())

def memStore():
    global memory
    memory = float(entry.get())

def grandTotal():
    global total,grandTotalFlag
    dataSet.clear()
    entry.set(total[0])

    if grandTotalFlag == False:
        total[0] = 0
        grandTotalFlag = True
    else:
        grandTotalFlag = False

entryFrame = tkinter.Frame(win,highlightthickness=1)
entryFrame.grid(column=0, row=0, padx=5, pady=5)

# entry number box
entry = tkinter.StringVar(entryFrame, value="0")
calculatorFont = tkinter.font.Font( family = "American Typewriter",
                                 size = 23,
                                 weight = "bold")
entry_txt = tkinter.Entry(entryFrame, textvariable=entry, font=calculatorFont, justify=tkinter.RIGHT)
entry_txt.grid(column=0, row=0)

frame0 = tkinter.Frame(win)
frame0.grid(column=0, row=1, padx=3,pady=5)

frame1 = tkinter.Frame(win, bg="white")
frame1.grid(column=0, row=2, padx=3,pady=5)

mcButton = tkinter.Button(frame0, text="MC", width=6, height=1,command=lambda : memClear())
mcButton.grid(column=0, row=0, pady=1, padx=1)

mrButton = tkinter.Button(frame0, text="MR",width=6, height=1, command=lambda : memRecall())
mrButton.grid(column=1, row=0, pady=1, padx=1)

mplusButton = tkinter.Button(frame0, text="M+",width=6, height=1,command=lambda : memAdd())
mplusButton.grid(column=2, row=0, pady=1, padx=1)

mminusButton = tkinter.Button(frame0, text="M-",width=6, height=1,command=lambda : memMinus())
mminusButton.grid(column=3, row=0, pady=1, padx=1)

msButton = tkinter.Button(frame0, text="MS", width=6, height=1,command=lambda : memStore())
msButton.grid(column=4, row=0, pady=1, padx=1)

mxButton = tkinter.Button(frame0, text="GT",width=6, height=1,command=lambda : grandTotal())
mxButton.grid(column=5, row=0, pady=1, padx=1)

percentageButton = tkinter.Button(frame1, text="%", width=10, height=3, command=lambda : percent())
percentageButton.grid(column=0, row=1, padx=3,pady=3)

ceButton = tkinter.Button(frame1, text="CE",width=10, height=3, command=lambda : clear("Partial"))
ceButton.grid(column=1, row=1, padx=3,pady=3)

cButton = tkinter.Button(frame1, text="C",width=10, height=3,command=lambda : clear("All"))
cButton.grid(column=2, row=1, padx=3,pady=3)

dButton = tkinter.Button(frame1, text="<-",width=10, height=3,command=lambda : delete())
dButton.grid(column=3, row=1, padx=3,pady=3)

deButton = tkinter.Button(frame1, text="1/x", width=10, height=3, command=lambda : otherOp("1/x"))
deButton.grid(column=0, row=2, padx=3,pady=3)

powButton = tkinter.Button(frame1, text="x\u00b2", width=10, height=3, command=lambda : otherOp("x\u00b2"))
powButton.grid(column=1, row=2, padx=3,pady=3)

squareRootButton = tkinter.Button(frame1, text="\u221Ax\u0305\u0305",width=10, height=3,command=lambda : otherOp("\u221Ax\u0305\u0305"))
squareRootButton.grid(column=2, row=2, padx=3,pady=3)

divideButton = tkinter.Button(frame1, text="\u00F7",width=10, height=3,command=lambda:insert("\u00F7"))
divideButton.grid(column=3, row=2, padx=3,pady=3)

sevenButton = tkinter.Button(frame1, text="7", width=10, height=3, command=lambda:insertNumber("7"))
sevenButton.grid(column=0, row=3, padx=3,pady=3)

eightButton = tkinter.Button(frame1, text="8", width=10, height=3, command=lambda:insertNumber("8"))
eightButton.grid(column=1, row=3, padx=3,pady=3)

nineButton = tkinter.Button(frame1, text="9",width=10, height=3,command=lambda:insertNumber("9"))
nineButton.grid(column=2, row=3, padx=3,pady=3)

timesButton = tkinter.Button(frame1, text="x",width=10, height=3,command=lambda:insert("x"))
timesButton.grid(column=3, row=3, padx=3,pady=3)

fourButton = tkinter.Button(frame1, text="4", width=10, height=3, command=lambda:insertNumber("4"))
fourButton.grid(column=0, row=4, padx=3,pady=3)

fiveButton = tkinter.Button(frame1, text="5", width=10, height=3, command=lambda:insertNumber("5"))
fiveButton.grid(column=1, row=4, padx=3,pady=3)

sixButton = tkinter.Button(frame1, text="6",width=10, height=3,command=lambda:insertNumber("6"))
sixButton.grid(column=2, row=4, padx=3,pady=3)

minusButton = tkinter.Button(frame1, text="-" ,width=10, height=3,command=lambda:insert("-"))
minusButton.grid(column=3, row=4, padx=3,pady=3)

oneButton = tkinter.Button(frame1, text="1", width=10, height=3, command=lambda:insertNumber("1"))
oneButton.grid(column=0, row=5, padx=3,pady=3)

twoButton = tkinter.Button(frame1, text="2", width=10, height=3, command=lambda:insertNumber("2"))
twoButton.grid(column=1, row=5, padx=3,pady=3)

threeButton = tkinter.Button(frame1, text="3",width=10, height=3,command=lambda:insertNumber("3"))
threeButton.grid(column=2, row=5, padx=3,pady=3)

plusButton = tkinter.Button(frame1, text="+",width=10, height=3,command=lambda:insert("+"))
plusButton.grid(column=3, row=5, padx=3,pady=3)

plusminusButton = tkinter.Button(frame1, text="+/-", width=10, height=3, command=lambda:plusminus())
plusminusButton.grid(column=0, row=6, padx=3,pady=3)

zeroButton = tkinter.Button(frame1, text="0", width=10, height=3, command=lambda:insertNumber("0"))
zeroButton.grid(column=1, row=6, padx=3,pady=3)

dotButton = tkinter.Button(frame1, text=".",width=10, height=3,command=lambda:insertDot())
dotButton.grid(column=2, row=6, padx=3,pady=3)

equalButton = tkinter.Button(frame1, text="=",width=10, height=3,command=lambda:insert("="))
equalButton.grid(column=3, row=6, padx=3,pady=3)

win.mainloop()

The above is the main.py file with a simple interface setup and a few functions to handle partial operations.

The calculate.py file will perform the remaining operations.

class Calculate:

    def __init__(self):
        pass

    def cal(self, data,entry, total):

        if(len(data) >=3):
            ans = 0
            if data[1] == "+" :
                ans = float(data[0]) + float(data[2])
                total[0] += ans
                data.clear()
                data.append(ans)
                entry.set(ans)
            elif data[1] == "-":
                ans = float(data[0]) - float(data[2])
                total[0]+=ans
                data.clear()
                data.append(ans)
                entry.set(ans)
            elif data[1] == "x":
                ans = float(data[0]) * float(data[2])
                total[0]+=ans
                data.clear()
                data.append(ans)
                entry.set(ans)
            elif data[1] == "\u00F7":
                if(float(data[2])!= 0.0):
                    ans = float(data[0]) / float(data[2])
                    total[0]+=ans
                    data.clear()
                    data.append(ans)
                    entry.set(ans)
                else:
                    data.clear()
                    entry.set("0")

Basically, the above file will do the arithmetics and returns the answer.

That is it! Only two files to create a simple calculator in Python. Without wasting time let us start to test the entire application. First of all, go to the application main page to download the application. If you are using windows 10 then you can directly download the main.exe file and run the application on your laptop. Or if you are using Linux or you prefer to run the main.py file then just go to the application main page and download both the main.py and calculate.py file then start the main.py program in the IDE such as pycharm! That is it, now let us begin the testing process.

The testing procedure of adding, subtracting, multiplying, and divide

Press these buttons on the application:

  1. 6 * 5 ꞊, you will get 30.0. Clear with the C button which will clear everything inside the memory but will not clear the grand total memory (GT which I will show you how to use it later on). Now let us continue with the substraction, divide and adding process!
  2. 5 – 6 ꞊, you will get -1.0. Press the C button again.
  3. 4 ÷ 5 ꞊, you will get 0.8. Press C again.
  4. 4 + 2 ꞊, you will get 6.0. Press C again.

What is the grand total of the above outcomes?

In order to get the grand total of the above outcome, press the GT button, you will get 35.8 (30+(-1)+0.8+6). Now press the GT button again to clear the memory of the grand total.

Let test the other functions

  1. Press 6 and then 1/x button then ꞊, you will get 0.166666. Press C.
  2. Press 3 and then x (square) button then ꞊ to get 9.0. Press C.
  3. Press 9 then the x (square root) button then ꞊ to get 3.0. Press C.
  4. Press 5 then the % button then ꞊ to get 0.05. Press C.
  5. Press 2 then press the +/- button to switch from +2 to -2 and -2 to +2. Press C.
  6. Enter any numbers then press the <- button to delete any number you want! Press C.
  7. The CE button is to clear the most recent entry, try this out, enter 5 then – then 9 then CE to clear 9 then – then 5 then ꞊, you will get 0 because 5 – 5 = 0.
  8. MC button is to clear the entire memory.
  9. Lets do this, press 6 + 7 =, then MS to store the answer inside the memory. Press C to clear. Next Press 3-4=, then press M+ to add the answer to the current memory, then press C to clear, next press 3 * 5 =, then press M- to minus the amount from the current memory, next press MR to recall and show the final answer on the screen. The answer is -3.0 (6+7+(-1)-15)!
  10. Finally, try out the significant figure, press 0 then . then 5 to make it 0.5!

Please go through extra testing on your own and let me know whether you have found any bug in the program or perhaps you would like to help me out by contributing to this project on Github!



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...