1

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?

chris
  • 13
  • 2
  • One problem is that you are passing in the button command by calling the function, instead of passing the function. Use `command=go` instead of `command=go()`. In addition, you should run root.mainloop() at the end. – thshea Jan 04 '21 at 13:53
  • 1
    There are plenty of mistakes here, I suggest you take a `tkinter` tutorial first. – Delrius Euphoria Jan 04 '21 at 13:53
  • 1
    Also instead of `sleep` I suggest the `after` method – JacksonPro Jan 04 '21 at 13:54

3 Answers3

1
  • 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)
  • Next would be to fix your entry widget and event driven programming. You shouldn't be taking the input from the user at the beginning of your code as it will be empty at the beginning. You should take the input and store it inside a variable after an event(a function or so) is triggered, which means your 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
  • Next thing is to avoid the usage of 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 ;)

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
0

First of all, when you pass a command into a button, you need to put the function without the parentheses: command=go. If you use parentheses, the function will be called when you declare the button instead of when you press it.

Secondly, you should not be calling root.mainloop() once the button is pushed. You should run that at the end of the file.

mainloop never returns, so putting sleep and a function call after does not help. If you want to run code during the main loop, make a loop that calls tk.update() and tk.update_idletasks().

I do not think that updated elements need to be packed again to update.

Finally, why are you calling go from inside itself?

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())


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()

root.geometry('300x200')
root.mainloop()
thshea
  • 1,048
  • 6
  • 18
0

Program based on your instructions should looks like this (similar):

from tkinter import *
import random
import time

# Create function, which generates random number and update label
def set_random_num():
    num = random.randint(0,100)
    lab2.config(text=num)

# Initialize tkinter window
root = Tk()

# Create labels and button
lab1 = Label(root, text='Type in number')
lab1.pack()

lab2 = Label(root, text='Number:')
lab2.pack()

b = Button(root, text='Go', command=lambda: set_random_num()) 
b.pack()

# Keep it at the end of program
root.mainloop() 

Lambda function allows you to call your function correctly. I recommend to look for some good tutorial for tkinter. Try this.

Author Climent
  • 83
  • 1
  • 1
  • 8