Support Forums

Full Version: [Tutorial] Advanced Tkinter Calculator
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Well this is my second Tkinter tutorial, my first can be found here This isn't really that advanced but it look's alot more like a normal calculator. If you follow this tutorial (if you didn't tweak anything) you should end up with this:
[Image: lol-2.png]

Now lets get started, today we will be using classes again, except this time we will be using a for loop to create the buttons. Before we start, you need to be familiar with the eval() function. All it does is take a string and treat it like an equation, like this:
Code:
>>> x = '5+6'
>>> eval(x)
11

Now let's get to the GUI part, here is the very top of our code and if this confuses you then you should go to my first tutorial:
Code:
from Tkinter import *

class calc(Frame):
    def __init__(self):
        global result
        top = Tk()
        top.title('UberCalc v2.0')
        Frame.__init__(self)
        result = Entry()
        result.pack(side=TOP)
So far the only thing we did visually is create a single text field at the top of the GUI that will hold the result. Now lets create two list, one will hold the numbers 0-9, a '.', and a 'Clear' button. The other list will hold our operators('+', '-', '*', '/', '=').
Code:
buttons = ['1', '2', '3','4', '5', '6','7', '8', '9','.', '0', 'Clear']
        operbtn = ['-','+', '*','/', '=']
Now we will be packing these buttons with the grid function so before we start creating buttons we need two integers that will act as our row and column numbers.
Code:
ro = 1
        col = 0
Ok now lets see the first for loop.
Code:
for x in buttons:
            action = lambda y=x: onclick(y)
            Button(self, text=x, width=5, relief='ridge', command=action).grid(row=ro, column=col)
            col += 1
            if col > 2:
                col = 0
                ro += 1
This may look intimidating so I will break it down for you. The lambda function is basically assigning a function to each button(which we define later) and the argument for the function is whatever item in the list the for loop is on. Next we create the button and put it in our "grid". Then, we keep increasing collumns until the column is greater than 2 (3), once it reaches 3 we reset the column to 0 and increment to row by 1, giving us 3 items in each row.
Now lets look at the second for loop:
Code:
col = 4
        ro = 1
        for x in operbtn:
            action = lambda y=x:onclick(y)
            Button(self, text=x, width=5, relief='ridge', command=action).grid(row=ro, column=col)
            ro += 1
Before we even create the buttons we need to set the column to 4 because we want all of our operator button's in the fourth column, then we reset the row to 1. We define our lambda function which tells the button to execute a function with the argument being itself, and we increment row by 1.
NOTE: The width and relief are style choices and aren't essential to our GUI so you can change them to whatever you think looks nicest.
Now we define our function to be called by the buttons(of course having an argument) and we need the result box so we use global to tell the GUI we will be working with result.
Code:
def onclick(key):
            global result
Next we simply tell our program that if the button clicked WAS NOT the '=' or 'Clear' button, Insert the button clicked into the result field.
Code:
if key != '=' and key != 'Clear':
                result.insert(END, key)
NOTE: The logical operator '!=' means "is not equal to" or "doesn't equal"
Now we say that if the button clicked IS '=', to fetch whatever is in the result box, evaluate it, and insert the answer.
Code:
if key == '=':
                fetch = result.get()
                answer = eval(fetch)
                result.delete(0, END)
                result.insert(0, answer)
Next all we need to do is tell it to clear out the result box if 'Clear' is pressed:
Code:
if key == 'Clear':
                result.delete(0, END)
Last but not least we add our "if __name__ == '__main__'" trick and our GUI is good to go:
Code:
if __name__ == '__main__':
    window = calc()
    window.pack()
    window.mainloop()
Now that you have the basic idea it should be easy to add your own buttons (memory, negate, etc.) and remember a lot of what is used here is simply my style preference so be sure to customize the appearance to whatever you like best.
Here is the full source:
Code:
from Tkinter import *

class calc(Frame):
    def __init__(self):
        global result
        top = Tk()
        top.title('UberCalc v2.0')
        Frame.__init__(self)
        result = Entry()
        result.pack(side=TOP)
        buttons = ['1', '2', '3','4', '5', '6','7', '8', '9','.', '0', 'Clear']
        operbtn = ['-','+', '*','/', '=']
        ro = 1
        col = 0
        for x in buttons:
            action = lambda y=x: onclick(y)
            Button(self, text=x, width=5, relief='ridge', command=action).grid(row=ro, column=col)
            col += 1
            if col > 2:
                col = 0
                ro += 1
        col = 4
        ro = 1
        for x in operbtn:
            action = lambda y=x:onclick(y)
            Button(self, text=x, width=5, relief='ridge', command=action).grid(row=ro, column=col)
            ro += 1

        def onclick(key):
            global result
            if key != '=' and key != 'Clear':
                result.insert(END, key)
            if key == '=':
                try:
                    fetch = result.get()
                    answer = eval(fetch)
                    result.delete(0, END)
                    result.insert(0, answer)
                except(ZeroDivisionError):
                    result.delete(0,  END)
                    result.insert(0,  'Do not divide by zero please')
                except(SyntaxError):
                    result.delete(0,  END)
                    result.insert(0,  '0')
            if key == 'Clear':
                result.delete(0, END)

if __name__ == '__main__':
    window = calc()
    window.pack()
    window.mainloop()

Edit: Updated to handle zero division error and string and int concatenation error.
This is pretty cool, however you should look into wxpython imo, much more powerful than tk
Cool. Learned something new.
very detailed great tut
Inspires me to learn more python
Very complicated lol



I will stick to VB.NET for now. Nice calculator though.
Wow, looks really nice. I will read the whole thing when I wake up tomorrow and start learning more python. Big Grin
nice tutorial dude! very helpful! Thanks! ;)
(04-05-2010, 06:00 PM)Fallen Wrote: [ -> ]This is pretty cool, however you should look into wxpython imo, much more powerful than tk

Yeah I know it is a lot better, I go for Tkinter only because its portable and doesn't demand OOP.