0

I started learning Tkinter and came across this piece of code for a 2 number calculator. After trying it out myself I noticed something and it confuses the hell out of me even after reading the documentation and playing with the console.

button_equal & button_clear don't use Parenthese under the command parameter. Why is that and why won't it work if I add them. From what I read I can see that when calling it with parentheses it calls and executes the function. But when called without parentheses it passes a reference? It's still all very fuzzy to me and I would love it if someone could dumb it down for me. Maybe with an example :)

import tkinter as tk

root = tk.Tk()
root.title("Mathz")

### Variables ##########################################################################
buttonWidth = 30
buttonHeight = 20
global f_number


### FUNCTIONS ##########################################################################################
def button_click(number):
    current = e.get()
    e.delete(0, tk.END)
    e.insert(0, str(current) + str(number))


def button_add():
    first_number = e.get()
    global f_num
    f_num = int(first_number)
    e.delete(0, tk.END)


def button_equal():
    second_number = e.get()
    e.delete(0, tk.END)
    e.insert(0, f_num + int(second_number))


def button_clear():
    e.delete(0, tk.END)


### Defining Widgets ###############################################################################

e = tk.Entry(root, width=35, borderwidth=5, bg='lightgrey')
e.grid(row=0, column=0, columnspan=3)

button_1 = tk.Button(root, text='1', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(1))
button_2 = tk.Button(root, text='2', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(2))
button_3 = tk.Button(root, text='3', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(3))
button_4 = tk.Button(root, text='4', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(4))
button_5 = tk.Button(root, text='5', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(5))
button_6 = tk.Button(root, text='6', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(6))
button_7 = tk.Button(root, text='7', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(7))
button_8 = tk.Button(root, text='8', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(8))
button_9 = tk.Button(root, text='9', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(9))
button_0 = tk.Button(root, text='0', padx=buttonWidth, pady=buttonHeight, command=lambda: button_click(0))
button_plus = tk.Button(root, text='+', padx=buttonWidth - 1, pady=buttonHeight, command=lambda: button_add())
button_equal = tk.Button(root, text='=', padx=69, pady=buttonHeight, command=button_equal)
button_clear = tk.Button(root, text='Clear', padx=buttonWidth * 2, pady=buttonHeight, command=button_clear)

### Positioning Widgets ######################################################################################

button_1.grid(row=3, column=0)
button_2.grid(row=3, column=1)
button_3.grid(row=3, column=2)

button_4.grid(row=2, column=0)
button_5.grid(row=2, column=1)
button_6.grid(row=2, column=2)

button_7.grid(row=1, column=0)
button_8.grid(row=1, column=1)
button_9.grid(row=1, column=2)

button_0.grid(row=4, column=0)
button_clear.grid(row=4, column=1, columnspan=2)
button_equal.grid(row=5, column=1, columnspan=2)

button_plus.grid(row=5, column=0)

root.mainloop()
Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
itsolidude
  • 1,119
  • 3
  • 11
  • 22
  • If using `button_add` works, why aren't you using `button_equal` and `button_clear` the same way? – Scott Hunter Mar 20 '21 at 11:25
  • If you aren't using parentheses, you aren't calling it. – Scott Hunter Mar 20 '21 at 11:25
  • Does this answer your question? [Why is the command bound to a Button or event executed when declared?](https://stackoverflow.com/questions/5767228/why-is-the-command-bound-to-a-button-or-event-executed-when-declared) – Thingamabobs Mar 24 '21 at 21:00

2 Answers2

3

Best way to start and to learn what is going on here, I guess is to point out that tkinter is based on another programming language, called tcl. tkinter is a GUI package in tcl and works with python through a wrapper. So you need to understand a little of both languages here to understand what is going on.

First consider this code here:

import tkinter as tk

def func():
    print('func is running')

root = tk.Tk()
b = tk.Button(root, text='exampel', command=func)
b.pack()
root.mainloop()

This is a standard script of creating a window, with a button that can be executed. If you would add a line of code before root.mainloop() that has the form of this:

print(func)

Output for me

<function func at 0x03D803D8>

this is the information that is stored in this variable. It let you know that this is a object of function with the name func and you will find it at 0x03D803D8. This information will be interpreted by the wrapper of tkinter and transform it into a string of tcl code. You can proof that by this line:

print(b['command'])

Output

31262160func

This bit of code contains simliar information like python. It contains the information that this is a function and where to find it. I wrote in some depth how Functions & lambda works in python. But what you need to know for this question is just that the syntax () executes the function. After the execution it returns to that point it was called. In python you can return things like strings; integers; objects; etc that will be get in place where the function was called.


So lets consider this code here:

import tkinter as tk

def func():
    print('func is running')

def get_func():
    return func

root = tk.Tk()
b = tk.Button(root, text='exampel', command=get_func())
b.pack()

root.mainloop()

So what happens here is nonsense, but shows you how it goes. Apart from the code that we considered first we exchanged the function by the optional argument of command with the new function get_func(). Like I explained the function will be executed by the syntax () and with the statement return func we place that fnction object where we called it. So the codes looks more like this, after running:

b = tk.Button(root, text='exampel', command=func)

Add this bit of code here, somewhere over root.mainloop() to get more information of what happens here:

print(get_func)
print(get_func())
print('next')
print(func)
print(func())

Output

<function get_func at 0x02600390> #get_func function
<function func at 0x046303D8> #returned by get_function
next
<function func at 0x046303D8> #func function
func is running 
None #returned by func

Let me know if some questions are left.


Update

I still get confused since you called just func and not func() via command.

The func is stored with the information like I already explained. The parantheses are just like a synonym for run that function. What you generally want to do is to store the function and call it when the Click_Event is happen and not to run that function while the Button is built up. So just imagin that the () is added on the stored function everytime the Click_Event is happen.

I hope you accept this as an answer. Because further more question would include much more information about Class;Eventloop and much more.

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • First of all, thank you for such a detailed read. Made a whole other things for me very clear. When you said `syntax () executes the function` I still get confused since you called just `func` and not `func()` via `command`. Shouldn't that mean that the function won't execute? Or is it because it does not actually return any values? – itsolidude Mar 20 '21 at 21:21
0

When you are using the parameter: command=button_equal you are telling the button which function to call.

When the button itself is clicked, it then knows which function to call and it calls it at that time and not sooner or later.

quamrana
  • 37,849
  • 12
  • 53
  • 71
  • So when I click the button in the background it calls `button_equal()`. But why won't it work using `button_equal` with Parenthese straight away? I mean the lambda functions use them too? – itsolidude Mar 20 '21 at 11:32
  • 1
    The `lambda` function is just that. A function. And when you use `command=lambda: button_add()`, you are creating a `lambda` function and telling the button which function to call. When the button itself is clicked, then it knows which function to call. And it does so at the right time. When called, the `lambda` function executes its contents, which is `button_add()`. – quamrana Mar 20 '21 at 11:35