-1

I implement a python program with tkinter and I want to show the result from fct1 after I click the button. When I run the program the result appears in the window even if I did not click the button.

from tkinter import *

def fct1():
 u = 0.1
 while 1 + u != 1:
  u /= 10
return u * 10

def create_gui():
 window = Tk()
 window.title("Math")
 window.geometry('350x200')
 label1 = Label(text=' ')
 label1.grid(column=2, row=0)
 btn = Button(window, text="Function1", command=clicked(label1))
 btn.grid(column=1, row=0)
 window.mainloop()

def clicked(label1):
 output = fct1()
 label1['text']=str(output)

create_gui()
Alex544
  • 25
  • 4

2 Answers2

1

I think you should refactor your code a bit. The tkinter GUI is better off in the global namespace or in a class. That said your command wont work due the parenthesis. What happens is the command is called only once at init with parenthesis so you need to call the command without them or within a lambda function.

Cleaned up example:

import tkinter as tk


def fct1():
    u = 0.1
    while 1 + u != 1:
        u /= 10
    return u * 10


def clicked():
    label1['text'] = fct1()


window = tk.Tk()
window.title("Math")
window.geometry('350x200')
label1 = tk.Label(text=' ')
label1.grid(column=2, row=0)
tk.Button(window, text="Function1", command=clicked).grid(column=1, row=0)
window.mainloop()

Better yet use a class. You can avoid a lot of issues this way:

import tkinter as tk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Math")
        self.geometry('350x200')
        self.label1 = tk.Label(self, text=' ')
        self.label1.grid(column=2, row=0)
        tk.Button(self, text="Function1", command=self.clicked).grid(column=1, row=0)

    def clicked(self):
        self.label1['text'] = self.fct1()

    def fct1(self):
        u = 0.1
        while 1 + u != 1:
            u /= 10
        return u * 10


App().mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
1

The reason is explained by mike - smt in the comments, it is because with the parenthesis, Python executes the function at the time the code is read but without them (the parenthesis), python treats it as a reference to the function that it can call later.

I have found the best way to avoid this is to use the lambda function.

It is best explained here but I will try to summarise it here

As I said, when a button is created it will run the command that you want to be run when it is clicked.

To create a lambda function that calls your button function with an argument you would do something like this:

lambda: button('ping pong')

You end up with a function that is functionally equivalent to:

def function():
    button('ping pong')

lambda returns a reference to this nameless function. Since a reference is what the command option expects you can use lambda directly in the creation of the button

so instead of

btn = Button(window, text="Function1", command=clicked(label1))

use the lambda function to call your custom function like this

btn = Button(window, text="Function1", command=lambda: clicked('label1'))
mmoomocow
  • 1,173
  • 7
  • 27
  • *Tkinter runs button functions when they are created*... not quite. Tkinter has nothing to do with this behavior. It is just how Python does things. The reason is that with the parenthesis in place python executes the function at the time the code is read but without them python treats it as a reference to the function to be called later. – Mike - SMT Feb 21 '20 at 19:09
  • @Mike-SMT thanks for that, I'll edit the answer and fix that – mmoomocow Feb 21 '20 at 19:16