I didn't test it but real problem is command=cl_s() which is wrong.
command= needs function's name without () - command=cl_s - and when you press button then python will use () to run this cl_s.
At this moment it runs cl_s() at once and it runs while-loop which is blocking all code when you set b=True and it can't run .pack() to show button.
When you remove b=True then it skips loop while b: and it can run .pack() to show button.
If you add some print() inside cl_s() and inside while b: then you will see this.
If you add also print() after start = ... then you will see that this is not executed when you set b = True
Mininal working code (with mainloop() to work even without IDLE or Thonny)
But I would also use root.after(1000, function) instead of while-loop and sleep(1) and .update()
import tkinter as tk
import time # PEP8: preferred to put every module in separate line
# --- classes --- # PEP8: all classes after imports
# --- functions --- # PEP8: all functions after classes
def cl_e():
global b # inform function to use global variable instead of creating local one
b = False
def cl_s():
global b # inform function to use global variable instead of creating local one
b = True # need it to run again after pressing `End` and `Start` again
#print("running cl_s")
h = 0
m = 0
s = 0
while b:
#print("running while b")
if s < 60:
s += 1
time.sleep(1)
elif m < 60:
s = 0
m += 1
else:
s = 0
m = 0
h += 1
txt = f"{h:02}:{m:02}:{s:02}" # format numbers with 2 digits, with leading zero
canvas.delete("all")
canvas.create_text(250, 250, text=txt, font="Arial 70 bold")
canvas.update()
# --- main ---
# global b # variables created outside functions/classes are global
b = True # this is already global variable
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500, bg="white")
canvas.pack()
canvas.create_text(250, 250, text="00:00:00", font="Arial 70 bold")
start = tk.Button(root, text="Start", command=cl_s)
#print("after start")
start.pack()
end = tk.Button(root, text="End", command=cl_e)
#print("after end")
end.pack()
root.mainloop()
PEP 8 -- Style Guide for Python Code
The same with root.after() instead of while-loop.
I have to change if/elif/else because function is repeated always after 1000ms, but original version was running sleep(1) only in some situations.
I also use counter = canvas.text(...) and canvas.itemconfig(counter, ...) to replace text in existing widget without deleting it and creating it again.
And I also use more readable names - running instead of b, clock_start instead of cl_s, and clock_end instead of cl_e
import tkinter as tk
import time # PEP8: preferred to put every module in separate line
# --- classes --- # PEP8: all classes after imports
# --- functions --- # PEP8: all functions after classes
def clock_end():
global running # inform function to use global variable instead of creating local one
running = False
def clock_start():
global running
running = True
# clear previous text
canvas.itemconfig(counter, text="00:00:00")
# start after 1000ms (1s) with h=0, m=0, s=0
root.after(1000, counting, 0, 0, 0)
def counting(h, m, s):
if running:
s += 1
if s == 60:
s = 0
m += 1
if m == 60:
m = 0
h += 1
txt = f"{h:02}:{m:02}:{s:02}" # format numbers with 2 digits, with leading zero
# replace text without creating widget again
canvas.itemconfig(counter, text=txt)
root.after(1000, counting, h, m, s) # repeat after 1000 ms
# --- main ---
running = True # this is already global variable
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500, bg="white")
canvas.pack()
counter = canvas.create_text(250, 250, text="00:00:00", font="Arial 70 bold")
start = tk.Button(root, text="Start", command=clock_start)
start.pack()
end = tk.Button(root, text="End", command=clock_end)
end.pack()
root.mainloop()
tkinter.mainloop()at the end and atkinter.Tk()at the start. Is there a particular reason for that? Are you new to the library?if/elif/elseyou runcanvas.delete("all")andcanvas.update()so you could move it outsideif/elif/else. You could runcanvas.delete("all")beforeif/elif/elseandcanvas.update()afterif/elif/elseButtononCanvasthen you should rather usecanvas.createwindow(your_button)instead of.pack()command=needs function's name without(). Went you press button then tkinter will use()to execute this function - so you needcommand=cl_s,command=cl_e. Maybe this makes problem because it may runcl_s()(andwhile-loop may block next lines) before it runs.pack()to show button.global bonly inside function to inform it that it has to use external/global variable instead of creating local variable.