1
import random
import time
from tkinter import *    

root = Tk()

x = ""

lab = Label(root,text = x)
lab.pack()

root.mainloop()

def randomno():
    while (1):
        y = random.randint(1, 100)
        y = StringVar()
        x = y.get()
        lab["text"] = x
        #root.update_idletasks()
        time.sleep(2)

randomno()

Error:

Traceback (most recent call last):   File
   "C:/Users/Acer/PycharmProjects/unseen/tp.py", line 26, in <module>
       randomno()   File "C:/Users/Acer/PycharmProjects/unseen/tp.py", line 20, in randomno
       y = StringVar()   File "C:\Users\Acer\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py",
   line 480, in __init__
       Variable.__init__(self, master, value, name)   File "C:\Users\Acer\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py",
   line 317, in __init__
       self._root = master._root() AttributeError: 'NoneType' object has no attribute '_root'
martineau
  • 119,623
  • 25
  • 170
  • 301

2 Answers2

0

This is because your code intentions are wrong. I recommend you to organize your program with class structure. Furthermore, your infinite loop blocks the tkinter mainloop, so even you fixed your code, your window will freeze. So here is the working example:

import random
import time
from threading import Thread
from tkinter import *


class stack_overflow():
  def __init__(self, master):
      self.master = master
      self.x = 'trial'

      self.lab = Label(self.master, text=self.x)
      self.lab.pack(side="left")
      self.start_radome()

  def start_radome(self):
      radome_thread = Thread(target=self.randomno)
      radome_thread.start()

  def randomno(self):
      while True:
          self.x = random.randint(1, 100)
          self.lab.config(text='%s' % self.x)
          time.sleep(1)

if __name__ == '__main__':
      root = Tk()
      app = stack_overflow(master=root)
      root.mainloop()

So you start yout tkinter, which is your main thread. The starting your infinite loop in another thread. Hence, your tkinter window will not freeze.

Aybars
  • 395
  • 2
  • 11
  • There are simpler ways to do this using `tkinter`'s own widget [`after()`](http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/universal.html) method. – martineau Dec 14 '18 at 08:27
  • @martineau hello, you are right. It can be done. But soon or later you might need to add more functions to your tkinter, so I think thread mechanism is more maintainable. And for calling a function or process periodically, maybe `queue` is better. I would like to hear your opinion, thanks. – Aybars Dec 14 '18 at 08:39
  • Threading can be useful too, but unlike using `after()` you have to be very careful to only make tkinter calls in the main thread (or say a separate gui-only thread). I posted an [answer](https://stackoverflow.com/a/53528140/355230) to a related question not long ago the provides a template/recipe for using threads you might be interest in. Queues ar often using in tkinter apps to all the other thread(s) to communicate with the GUI, but notice that `after()` is still being used and the function it calls can make tkinter calls based in info it gets from the queue. – martineau Dec 14 '18 at 10:02
  • @martineau thank you for your reply. I have checked your post. Useful information especially running background function within a tkinter app. – Aybars Dec 14 '18 at 10:15
  • I guess the takeaway is, that for something as trivial as modifying the text of a `Label` in a uniform way that requires no additional information and can be done quickely, using a separate thread (and possibly a `Queue`) would be way overkill—and probably slower although that may not matter. – martineau Dec 14 '18 at 10:25
0

Here's the common way to do what you want in tkinter:

import random
import time
import tkinter as tk

DELAY = 2000  # milliseconds (thousandth of a second)

def randomno():
    x = random.randint(1, 100)
    lab["text"] = x
    #time.sleep(2)  # Don't call this in a tkinter program!
    root.after(DELAY, randomno)  # Call this function again after DELAY ms.


root = tk.Tk()

lab = tk.Label(root, text="")
lab.pack()

randomno()  # Starts periodic calling of itself.
root.mainloop()

You don't need to use a StringVar and can just assign the new random value in the randomno() function.

You shouldn't call time.sleep() in a tkinter application. Use the universal widget method after() instead. Notice how in the code above how randomno() calls root.after() to arrange for itself to be called again later.

That's how to do something periodically in a tkinter program, and this approach will keep the GUI running not "hang" when sleep() is called.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • thanx alot @martineau for help. – user9920858 Dec 14 '18 at 09:10
  • user9920858: You're welcome. Also note that with this approach you can have other widgets displayed and be able to interact with them while the Label keeps getting update in the "background"—all because `mainloop()` is still running, – martineau Dec 14 '18 at 10:09