title: Starting a thread from within a tkinter widget
body: <p>First, I have to say that I am not an expert at Python. Most of the code I gleaned from examples.</p>
  
  <p>I have done a fair bit of research and haven't been able to find a code configuration that is like what I am trying to do: start a thread from within a custom widget class. I understand that tkinter has issues with multiple threads trying to communicate with a single widget but I don't see that as the case here.</p>
  
  <p>The reason I'm trying to do this is so that each widget can be started/stopped and updated on it's own. This way I can view data from multiple sources from within the same root window and each source can be added/removed at will. I understand that I could code this differently (all in a single class) but I wanted to try it this way. I thought it would make things cleaner.</p>
  
  <p>My thought process on this is as follows:</p>
  
  <ol>
  <li>Create a reusable custom widget class.</li>
  <li>Be able to add multiple widgets to the root window (and also be able to remove them)</li>
  <li>Each widget will get data and update itself independent from the others.</li>
  <li>Use threading so that each widget will do what it needs to do in the background. That way all widgets will update at the same time.</li>
  </ol>
  
  <p>My code example shows the basics of what I am trying to accomplish. In the finished program, each widget will have a text box defining where to get it's data.</p>
  
  <p>This test code works fine using Python3 in WindowsXP. Each widget can be added and removed, and will update itself independently from the others.</p>
  
  <p>When I run this same code using Python3 in Fedora20, it crashes when the start button is pressed. The exception is the following:</p>
  
  <pre class="lang-none prettyprint-override"><code>Exception in thread Thread-1:
  Traceback (most recent call last):
  File "/usr/lib/python3.3/threading.py", line 637, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.3/threading.py", line 594, in run
    self._target(*self._args, **self._kwargs)
  File "dummy.py", line 44, in updlabel
    self.label.config(text=number)
  File "/usr/lib/python3.3/tkinter/__init__.py", line 1263, in configure
    return self._configure('configure', cnf, kw)
  File "/usr/lib/python3.3/tkinter/__init__.py", line 1254, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
  _tkinter.TclError: None
  </code></pre>
  
  <p>So ultimately, I have 2 questions:</p>
  
  <ol>
  <li>Why doesn't it work in linux while it does in WindowsXP?</li>
  <li>Is my approach a valid one and if so, where is my problem in this code?</li>
  </ol>
  
  <p>Code Example:</p>
  
  <pre class="lang-py prettyprint-override"><code>from threading import Thread
  import tkinter as tk
  import numpy as np
  import time
  
  class Widget(tk.Frame):
      def __init__(self, master):
          tk.Frame.__init__(self, master)
  
          self.running = False
          self.abort = True
  
          labelfont = ('times', 20, 'bold')
  
          self.label = tk.Label(self, text="---", font=labelfont)
          self.startb = tk.Button(self, text="START", command=lambda: self.sbpressed())
          self.remove = tk.Button(self, text="-", command=lambda: self.rbpressed())
  
          self.startb.grid(row=0, column=0)
          self.label.grid(row=0, column=1)
          self.remove.grid(row=0, column=2)
  
      def rbpressed(self):
          self.abort = True
          while self.running:
              self.update()
          self.destroy()
  
      def sbpressed(self):
          if self.running:
              self.abort = True
              self.update()
          else:
              self.startb["text"] = "ABORT"
              self.running = True
              self.abort = False
              self.update()
              self.t = Thread(target=self.updlabel, args=())
              self.t.start()
  
      def updlabel(self):
          while self.abort == False:
              number = str(np.random.random_integers(100))
              self.label.config(text=number)
              time.sleep(1)
          self.startb["text"] = "START"
          self.running = False
          self.abort = False
  
  class Application(tk.Frame):
      def __init__(self, master=None):
          tk.Frame.__init__(self, master)
          self.pack()
          self.addb = tk.Button(self, text="+", command=lambda: self.addwidget())
          self.addb.pack()
          Widget(self).pack()
  
      def addwidget(self):
          Widget(self).pack()
  
  root = tk.Tk()
  app = Application(master=root)
  app.mainloop()
  </code></pre>