By clicking the Start button, the value on label must be increased by 3 every 500 milliseconds until I destroy the window, but the value is stuck on 0.
from tkinter import *
def start(value):
value =3
label['text']=str(value)
if True:
root.after(500, start, value)
def stop():
root.destroy()
root = Tk()
root.geometry("420x250")
value = 0
label = Label(root, background="pink", width=20, height=2, text = str(value))
label.pack(anchor=W, pady=5)
btn1 = Button(root, text="Start", width=6, height=2, command=start).pack(
side=LEFT, anchor=NW, padx=2, pady=2)
btn2 = Button(root, text="Stop", width=6, height=2, command=stop).pack(
side=LEFT, anchor=NW, pady=2)
root.mainloop()
CodePudding user response:
The reason your code doesn't work is because the command=start
for the Start button isn't passing it the parameter the start()
function expects. That could be fixed by removing the parameter from the function's definition and modifying it to directly access the global
variable.
However I think it would be better in this case to use a tkinter's "Variable Classes" to do things given what else it looks like what you're trying to do. (See The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar) for a little documentation.) One of the most useful features they have is that they can be used in many widgets (such as Label
s) instead of supplying a static text string. When that's done, the widget's display of the variable's value will automatically get update itself whenever the value of tkinter.Variable
changes.
Below is example code showing how to use them which also makes use of an additional tkinter.Variable
to hold the value of a boolean flag the controls whether the updating is enabled. I also added a third Button
to quit since I changed what the Stop button does in your code.
from tkinter import *
def start():
incflag_var.set(True)
inc_value() # Start incrementing.
def inc_value():
value_var.set(value_var.get() 3) # Will auto update label.
if incflag_var.get():
root.after(500, inc_value)
def stop():
incflag_var.set(False)
root = Tk()
root.geometry("420x250")
value_var = IntVar(value=0)
incflag_var = BooleanVar(value=False)
label = Label(root, background="pink", width=20, height=2, textvariable=value_var)
label.pack(anchor=W, pady=5)
Button(root, text="Start", width=6, height=2, command=start).pack(
side=LEFT, anchor=NW, padx=2, pady=2)
Button(root, text="Stop", width=6, height=2, command=stop).pack(
side=LEFT, anchor=NW, pady=2)
Button(root, text="Quit", width=6, height=2, command=root.quit).pack(
side=LEFT, anchor=NW, pady=2)
root.mainloop()
CodePudding user response:
As it turns out tkinter.Label
can support int
eger values too, so the way you can do incrementing is by simply using label["text"] = 3
if the starting text
of the label is an int
eger (or float
probably works too).
You also need to not let it create multiple after
"loops" so setting some flags and checking those also should be added, the way I implemented it is by creating an attribute for that same label that tells whether it has started counting and if it hasn't then start.
import tkinter as tk
def start():
if not getattr(label, "counting", False):
update()
label.counting = True
def stop():
root.destroy()
def update():
label["text"] = 3
root.after(500, update)
root = tk.Tk()
root.geometry("420x250")
label = tk.Label(root, background="pink", width=20, height=2, text=0)
label.pack(anchor="w", pady=5)
tk.Button(root, text="Start", width=6, height=2, command=start).pack(
side="left", anchor="nw", padx=2, pady=2
)
tk.Button(root, text="Stop", width=6, height=2, command=stop).pack(
side="left", anchor="nw", pady=2
)
root.mainloop()
Also note that there is no point in assigning the returned values of pack
(or grid
or place
) to a variable, you can just simply create buttons without those variables, label
on the other hand of course needs to be referenced so it's properly made for that.
Also:
I strongly advise against using wildcard (*
) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2
and so on or import the whole module: import module
then You can also use an alias: import module as md
or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.