I made a little script to practice the use of tkinter. I want the program to open a window and show a label. The label should show a random number between 0 and 100 once I press the button. Also I want the label to refresh every second and show another random number.
from tkinter import *
import random
import time
root = Tk()
def getrandint():
result = random.randint(0, 100)
return result
def go():
lab2['text'] = 'Number: ' + str(getrandint())
lab2.pack()
root.geometry('300x200')
root.mainloop()
time.sleep(1)
go()
lab1 = Label(root, text='Type in number')
lab2 = Label(root, text='Number:')
#ent = Entry(root, width=20)
#number = ent.get()
b = Button(root, text='Go', command=go())
b.pack()
lab1.pack()
lab2.pack()
#ent.pack()
This is how far I got. It opens a window and shows a random number, but isn't refreshing the number. The Button isn't even showing. Also, when I close the window, Python 3.8 shows me this error message:
Traceback (most recent call last):
File "C:/Users/chris/Desktop/WeatherLinkPy/testing.py", line 102, in <module>
b = Button(root, text='Go', command=go())
File "C:/Users/chris/Desktop/WeatherLinkPy/testing.py", line 95, in go
go()
File "C:/Users/chris/Desktop/WeatherLinkPy/testing.py", line 89, in go
lab2['text'] = 'Number: ' + str(getrandint())
File "C:\Users\chris\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1660, in __setitem__
self.configure({key: value})
File "C:\Users\chris\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1649, in configure
return self._configure('configure', cnf, kw)
File "C:\Users\chris\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1639, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!label2"
Finally, is there a way to change the second parameter of random.randint(0, b) with an entry and a button at the beginning?
Lets start with the basic mistakes, your placement of mainloop()
decides what all widgets are displayed(on a well written code). In this case, you want to put mainloop()
at the end. In you case this even work because you were using ()
with the button that has the function which contains mainloop()
(a little tricky to explain through words :P).
Now the next is, you shouldn't be calling the function using ()
for your buttons, as it will start the function automatically and will not wait for the button to be pressed:
b = Button(root, text='Go', command=go)
getrandint()
will be:def getrandint():
try: # To ignore if non integers are entered into the entry widget
result = random.randint(0, int(ent.get())) # Get the text from entry widget
return result
except TypeError: # Ignore the error
pass
time.sleep()
as it will lag the GUI. So you should instead use root.after(ms,func)
which will call the func
after a specified ms
:def go():
lab2['text'] = 'Number: ' + str(getrandint())
root.after(1000,go) # Repeat the function after 1 second
So your final code would be:
from tkinter import *
import random
root = Tk()
root.geometry('300x200')
def getrandint():
try:
result = random.randint(0, int(ent.get()))
return result
except TypeError:
pass
def go():
lab2['text'] = 'Number: ' + str(getrandint())
root.after(1000,go)
lab1 = Label(root, text='Type in number')
lab2 = Label(root, text='Number:')
ent = Entry(root, width=20)
b = Button(root, text='Go', command=go)
b.pack()
lab1.pack()
lab2.pack()
ent.pack()
root.mainloop() # At the end of the code
Also note:
You can completely get rid of your getrandint()
by changing your go()
into:
def go():
try: # If not an integer is entered into entry widget
lab2['text'] = 'Number: ' + str(random.randint(0,int(ent.get())))
root.after(1000,go)
except ValueError: # Ignore the error
pass
With all this being said, your error happens due to the way your code flows. Practice more often keeping these in mind, and you shall never see these errors again ;)