-1

I want to creates buttons in a while loop, but when the app starts running, my program stops. It might be a beginner problem, but I cannot figure it out.

My code looks like this:

import tkinter as tk

app = tk.Tk()
app.geometry("600x300")
app.title("Test App")
con = tk.Frame(app)

ran = False
clicked = False

def setClicked():
    globals()['clicked'] = True

while True:
    if ran != True:
        btn = tk.Button(con, text="Clickmepls", command=lambda: setClicked())
        btn.pack(side=tk.TOP)
        app.update()
        con.pack()
        ran = True
        print("Lemme run")
    else:
        if clicked == True:
            ran = False
            clicked = False
            print("You ran")
        else:
            app.update()
        
    
app.mainloop()

I tried putting pack and mainloop outside the while loop, which results in the program not starting. I tried adding update and update_idletasks but it didn't work.

4
  • 2
    Why do you think you need that loop and clicked in the first place? Commented Oct 13 at 13:37
  • How do you know the program "stopped"? Is it because the program's not responding to clicks? If so, this is answered by How to bind a click event to a Canvas in Tkinter?. Commented Oct 13 at 13:39
  • well its a sample code, the original seemed too long. after a bit of testing a found out that using update() after btn.pack() and putting pack and mainloop outside the loop works. so it just needs to update alltime. Commented Oct 13 at 13:48
  • 1
    What do you want to achieve with the while loop actually? Commented Oct 13 at 15:09

2 Answers 2

2

You have a fundamental misunderstanding of how Tk works.

Tk is an event driven system.

You create your widgets and tell them what to do when something happens to them. This is through the command= argument to the widget creation commands.

You then start the mainloop() and let Tk do its thing. mainloop() will wait for the user to do something with the app and invoke the appropriate event handler (command) as needed.

Here is an alternative to your code:

import tkinter as tk

app = tk.Tk()
app.geometry("600x300")
app.title("Test App")
# No Frame needed - a Frame is a _separate_ window from the main application window
# con = tk.Frame(app)

def handleClick():
    # this is called whenever the button is pressed.
    # If `clicked` is False, change the button to `Clickmepls`
    # and display `Lemme run` in the message label.
    # If `clicked` is True, change the button to `Clickmetoo`
    # mark clicked, btn, and msg as global variables
    global clicked
    global btn
    global msg
    if clicked:
        btn["text"] = "Clickmetoo"
        msg["text"] = "When's my turn?"
    else:
        btn["text"] = "Clickmepls"
        msg["text"] = "Lemme run"
    clicked = not clicked

# NOTE - widgets must be created with a parent as the first argument (`app`)
btn = tk.Button(app, command=handleClick)

# Use a label to replace the `print` statements
msg = tk.Label(app)

# use `handleClick` to set the initial button and label text
clicked = False
handleClick()

# only pack the widgets once their initialization is complete
btn.pack(side=tk.TOP)
msg.pack(side=tk.BOTTOM)

app.mainloop()
Sign up to request clarification or add additional context in comments.

Comments

0

You are using Tkinter as loop-driven which is wrong. Tkinter is event-driven.

In your code you use a while True: loop plus calls to app.update(). The correct approach is to create your widgets (buttons, labels) once, and then use their command= callback functions to handle clicks and changes. Then call app.mainloop() to let Tkinter handle the event loop internally.

Here’s a another version of your code with the same functionality

import tkinter as tk
def handle_click():
global clicked, btn, msg
if clicked:
btn["text"] = "Clickmetoo"
msg["text"] = "When's my turn?"
else:
btn["text"] = "Clickmepls"
msg["text"] = "Lemme run"
clicked = not clicked
app = tk.Tk()
app.geometry("600x300")
app.title("Test App")

clicked = False
btn = tk.Button(app, text="Clickmepls", command=handle_click)
msg = tk.Label(app, text="")

btn.pack(side=tk.TOP)
msg.pack(side=tk.BOTTOM)

app.mainloop()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.