Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tutorial] Advanced Tkinter Calculator
#1
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.
[Image: izsyo6.jpg]


Reply
#2
This is pretty cool, however you should look into wxpython imo, much more powerful than tk
[Image: nv70ad.png]
Terrorcore, unleash, extermination
Hyper real, cold blood, determination
fudge them, I like this sensation
Incredible, I from the annihilation
Reply
#3
Cool. Learned something new.
[Image: deities.jpg]
Reply
#4
very detailed great tut
Reply
#5
Inspires me to learn more python
Reply
#6
Very complicated lol



I will stick to VB.NET for now. Nice calculator though.
Site Owner: http://www.awesomelounge.com

Feel free to join. It's full of greatness.


[Image: s1ckl3r2.png]
Reply
#7
Wow, looks really nice. I will read the whole thing when I wake up tomorrow and start learning more python. Big Grin
Reply
#8
nice tutorial dude! very helpful! Thanks! ;)
Reply
#9
(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.
[Image: izsyo6.jpg]


Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How to display variable serial data on Tkinter window. srinivas.rambha 0 1,005 06-17-2013, 05:54 AM
Last Post: srinivas.rambha
  Tkinter movable Dot? nevets04 4 2,038 03-06-2010, 05:26 PM
Last Post: nevets04
  Complete Tkinter Calculator uber1337 0 1,756 03-06-2010, 09:49 AM
Last Post: uber1337
  [Tutorial] Basic Tkinter Calculator uber1337 0 7,179 02-20-2010, 12:44 PM
Last Post: uber1337
  Calculator Using Object Oriented Programming nevets04 1 2,405 11-16-2009, 04:12 PM
Last Post: Fallen

Forum Jump:


Users browsing this thread: 1 Guest(s)