I was just struggling with this myself, so I happen to have example code for a progressbar. In my case the subprocess is run as a thread within the same program, which makes knowing the relative progress of the work easier.
-
import gobject
-
import gtk
-
import threading
-
import time
-
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
self.work_complete = False
-
self.amount_completed = 0
-
gobject.timeout_add(100, self._update_bar)
-
-
for i in range(10):
-
time.sleep(0.3)
-
self.amount_completed += .1
-
-
self.work_complete = True
-
-
def _update_bar(self):
-
self.mainview.progressbar.set_fraction(self.amount_completed)
-
if self.work_complete:
-
self.mainview.progressbar.set_text("Complete!")
-
else:
-
self.mainview.progressbar.set_text("%d%%" % (self.amount_completed * 100))
-
return not self.work_complete
-
-
class MainView(gtk.Window):
-
def __init__(self):
-
gtk.Window.__init__(self)
-
self.connect('delete_event', self.handle_window_delete_event)
-
self.connect('destroy', self.quit)
-
-
self.progressbar = gtk.ProgressBar()
-
button1 = gtk.Button("Test")
-
button1.connect('clicked', self.button1_click)
-
box = gtk.VBox()
-
box.pack_start(self.progressbar)
-
box.pack_start(button1)
-
self.add(box)
-
-
def quit(self, *args):
-
gtk.main_quit()
-
-
def handle_window_delete_event(self, *args):
-
return False
-
-
def button1_click(self, *args):
-
self.progressbar.set_fraction(0)
-
worker = TestThread(self)
-
worker.start()
-
-
if __name__ == "__main__":
-
gobject.threads_init()
-
MainView().show_all()
-
gtk.main()
-
Here's a summary of the important aspects:
- gobject.threads_init() must be called if the application will use other threads
- The TestThread.run() method is run its own thread and it's not recommended to manipulate widgets directly from there.
- The TestThread.run() uses gobject.timeout_add() to register a callback method, which will be allowed to freely manipulate widgets and other GTK elements. The method will be called automatically with 100 millisecond intervalls. By returning False the callback method will be disabled.
- Obviously you have to have some way to measure the overall progress to show relevant "percent completed" info. You should calculate the fraction of downloaded bytes per total amount of bytes and assign it to the ProgressBar using ProgressBar.set_fraction(). If you cant know the relative progress I suggest you show a pendling progress bar without percentage info until the download hads completed.
I verified that the ProgressBar may be manipulated directly from the TestThread. However, I have had problems (segfaults, deadlocks, etc.) if widget manipulations have been performed from other threads than the GTK main thread.