title: Update a Gtk.ProgressBar from another thread or process
body: <p>I have a GUI with a progressbar. It should show the progress of the work a second thread does. I would like to have something like an event the thread can send to the GUIs progressbar immediatly on each step of the work. But I don't see how this could be done.</p>
  
  <p>Python itself offers a <code>Event</code> class for threading situations. But it would block the GUI main thread because of the <code>Event.wait()</code> methode.</p>
  
  <p>How does it change the situaton and possible solutions if the second thread is a process?</p>
  
  <p>My example here is based on PyGObject (Pythons Gtk) but is related to all other GUI libraries, too.
  The current solution works but it is IMO just a workaround. The GUI (as main thread) and the second (worker) thread sharing data via a threadsafe <code>queue.Queue</code>. There is a timer event in the GUI thread checking the qeueu in **fixed intervalls* for new data from the thread and updates the progressbar.</p>
  
  <pre><code>#!/usr/bin/env python3
  import time
  import threading
  import queue
  import gi
  gi.require_version('Gtk', '3.0')
  from gi.repository import Gtk, GLib
  
  
  class MyThread(threading.Thread):
      def __init__(self, queue, n_tasks):
          threading.Thread.__init__(self)
          self._queue = queue
          self._max = n_tasks
  
      def run(self):
          for i in range(self._max):
              # simulate a task 
              time.sleep(1)
              # put something in the data queue
              self._queue.put(1)
  
  
  class MyWindow(Gtk.Window):
      def __init__(self, n_tasks):
          Gtk.Window.__init__(self)
  
          # max and current number of tasks
          self._max = n_tasks
          self._curr = 0
  
          # queue to share data between threads
          self._queue = queue.Queue()
  
          # gui: progressbar
          self._bar = Gtk.ProgressBar(show_text=True)
          self.add(self._bar)
          self.connect('destroy', Gtk.main_quit)
  
          # install timer event to check the queue for new data from the thread
          GLib.timeout_add(interval=250, function=self._on_timer)
          # start the thread
          self._thread = MyThread(self._queue, self._max)
          self._thread.start()
  
      def _on_timer(self):
          # if the thread is dead and no more data available...
          if not self._thread.is_alive() and self._queue.empty():
              # ...end the timer
              return False
  
          # if data available
          while not self._queue.empty():
              # read data from the thread
              self._curr += self._queue.get()
              # update the progressbar
              self._bar.set_fraction(self._curr / self._max)
  
          # keep the timer alive
          return True
  
  if __name__ == '__main__':
      win = MyWindow(30)
      win.show_all()
      Gtk.main()
  </code></pre>