1. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jun 2013
Posts
2
Rep Power
0

#### Tkinter Help!

Hey guys, so I'm working on a simple calculator project for Python (using Tkinter) and have encountered a problem which, try as I might, cannot solve. Here's the code so far.

Code:
```from tkinter import *

root = Tk()
root.geometry("30x130")

def explain():
print("This is a simple calculator interface which can add and subtract values \nup to 999.")

def fillDisplay(x):
EntryBox.insert(0, str(x))

def clearDisplay():
EntryBox.delete(0, END)

EntryBox = Entry(root, width=7)
EntryBox.grid(row=0, columnspan=3)

for x in range(7, 10):
Button(root, text=str(x), command=fillDisplay(x)).grid(row=1, column=(x-7), sticky=W)

for x in range(4, 7):
Button(root, text=str(x), command=fillDisplay(x)).grid(row=2, column=(x-4), sticky=W)

for x in range(1, 4):
Button(root, text=str(x), command=fillDisplay(x)).grid(row=3, column=(x-1), sticky=W)

Button(root, text="0", command=fillDisplay(0)).grid(row=4, sticky=W)
Button(root, text="+").grid(row=4, column=1, sticky=W)
Button(root, text="-").grid(row=4, column=2, sticky=W)

Button(root, text="=", width=4).grid(row=0, column=5, rowspan=2, columnspan=2, stick=S)
Button(root, text="Clear", height=2, command=clearDisplay).grid(row=2, column=5, rowspan=2, columnspan=2, stick=N)

mainloop()```
So it's a pretty simple interface, with just the digits 0-9 (as buttons), a plus button, a minus button, an equals button and a clear button. There's also an Entry widget to be used as a display.

The problem:
The buttons 0-9 aren't working. Instead of pasting the number they have on them to the display when clicked, they do it at startup (so the Entry box starts out with 321654987 in it). No idea what's happening, it might be something to do with the way I have set up the "fillDisplay" function.
2. The primary cause of the problem is that the command option for the Button class c'tor expects a function or method, which would have to be passed without its argument list:

Code:
`    Button(root, text=str(x), command=fillDisplay).grid(row=1, column=(x-7), sticky=W)`
Unfortunately, this presents a different problem, in that the callback cannot take an argument, but the fillDisplay() function expects one. There is no way to pass the value to fillDisplay() as it is now defined.

The solution - a bit heavyweight, but nonetheless workable - is to define a subclass of the Button class, which should pass one of its methods as the callback.

Code:
``` class NumberButton(Button):
def __init__(self, parent, number, display):
Button.__init__(self, parent, text=number, command=self.fillDisplay)
self.value = number
self.display = display
def fillDisplay(self):
self.display.insert(0, str(self.value))```
Note that, in order to have the declaration of the new class as general as possible, I have both the parent window and the Entry box passed as arguments to the c'tor.

Now, this is all well and good, except that it inserts the values in the wrong order. A bit of string-shuffling will fix that, however. Below is a complete working version of your code.

Python Code:
```from tkinter import *
import tkinter.messagebox as mb

class NumberButton(Button):
def __init__(self, parent, number, display):
Button.__init__(self, parent, text=number, command=self.fillDisplay)
self.value = number
self.display = display

def fillDisplay(self):
curr_value = self.display.get()
if curr_value == '0':
new_value = str(self.value)
else:
new_value = ''.join([curr_value, str(self.value)])
self.display.delete(0, END)
self.display.insert(0, new_value)

def explain():
mb.showinfo("About", "This is a simple calculator interface which can add and subtract values \nup to 999.", icon=mb.INFO)

def clearDisplay():
EntryBox.delete(0, END)
EntryBox.insert(0, '0')

root = Tk()
root.geometry("175x140")
root.title = "Calculator"

EntryBox = Entry(root, justify=RIGHT, width=7)
EntryBox.grid(row=0, columnspan=3)
EntryBox.insert(0, '0')

# store a reference to the NumberButtons in a dictionary indexed on the
# value of the button
number = dict()
number[0] = NumberButton(root, 0, EntryBox).grid(row=4, sticky=W)
for x in range(7, 10):
number[x] = NumberButton(root, x, EntryBox).grid(row=1, column=(x-7), sticky=W)

for x in range(4, 7):
number[x] = NumberButton(root, x, EntryBox).grid(row=2, column=(x-4), sticky=W)

for x in range(1, 4):
number[x] = NumberButton(root, x, EntryBox).grid(row=3, column=(x-1), sticky=W)

Button(root, text="+").grid(row=4, column=1, sticky=W)
Button(root, text="-").grid(row=4, column=2, sticky=W)

Button(root, text="=", width=4).grid(row=0, column=5, rowspan=2, columnspan=2, stick=S)
Button(root, text="Clear", height=2, command=clearDisplay).grid(row=2, column=5, rowspan=2, columnspan=2, stick=N)

mainloop()```
3. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jun 2013
Posts
2
Rep Power
0
Wow, that was... amazing. Detailed, informative, just amazing man. You explained everything so that a noob like me could understand. ^^

Thanks a bunch!