views:

154

answers:

1

I'm having a problem with the code below. When I run it the progress bar will pulse for around 10 secs as meant to and then move on to downloading and will show the progress but when finished it will not move on to the next step it just locks up.

import sys
import time
import pygtk
import gtk
import gobject
import threading
import urllib
import urlparse

class WorkerThread(threading.Thread):

    def __init__ (self, function, parent, arg = None):
        threading.Thread.__init__(self)
        self.function = function
        self.parent = parent
        self.arg = arg
        self.parent.still_working = True

    def run(self): # when does "run" get executed?
        self.parent.still_working = True      
        if self.arg == None:
            self.function()
        else:
            self.function(self.arg)

        self.parent.still_working = False    

    def stop(self):
        self = None

class MainWindow:
    def __init__(self):
        gtk.gdk.threads_init()
        self.wTree = gtk.Builder()
        self.wTree.add_from_file("gui.glade")
        self.mainWindows()

    def mainWindows(self):
        self.mainWindow = self.wTree.get_object("frmMain")

        dic = { 
            "on_btnNext_clicked" : self.mainWindowNext,
        }
        self.wTree.connect_signals(dic)

        self.mainWindow.show()
        self.installerStep = 0 # 0 = none, 1 = preinstall, 2 = download, 3 = install info, 4 = install
        #gtk.main()
        self.mainWindowNext()

    def pulse(self):
        self.wTree.get_object("progress").pulse()

        if self.still_working == False:
            self.mainWindowNext()

        return self.still_working

    def preinstallStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 1
        WT = WorkerThread(self.heavyWork, self) #Would do a heavy function here like setup some thing
        WT.start()

        gobject.timeout_add(75, self.pulse)

    def downloadStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 2
        urllib.urlretrieve('http://mozilla.mirrors.evolva.ro//firefox/releases/3.6.3/win32/en-US/Firefox%20Setup%203.6.3.exe', '/tmp/firefox.exe', self.updateHook)

        self.mainWindowNext()

    def updateHook(self, blocks, blockSize, totalSize):
        percentage = float ( blocks * blockSize ) / totalSize
        if percentage > 1:
            percentage = 1

        self.wTree.get_object("progress").set_fraction(percentage)

        while gtk.events_pending():
            gtk.main_iteration()

    def installInfoStep(self):
        self.wTree.get_object("btnNext").set_sensitive(1)
        self.wTree.get_object("notebook1").set_current_page(1)
        self.installerStep = 3

    def installStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 4

        WT = WorkerThread(self.heavyWork, self) #Would do a heavy function here like setup some thing
        WT.start()

        gobject.timeout_add(75, self.pulse)

    def mainWindowNext(self, widget = None):
        if self.installerStep == 0:
            self.preinstallStep()
        elif self.installerStep == 1:
            self.downloadStep()
        elif self.installerStep == 2:
            self.installInfoStep()
        elif self.installerStep == 3:
            self.installStep()
        elif self.installerStep == 4:
            sys.exit(0)

    def heavyWork(self):
        time.sleep(10)

if __name__ == '__main__':
    MainWindow()
    gtk.main()

I have a feeling that its something to do with:

while gtk.events_pending():
    gtk.main_iteration()

Is there a better way of doing this?

A: 

Don't ever do this:

while gtk.events_pending():
   gtk.main_iteration()

Unless you really know what you are doing. And if you really do, do it like this:

def refresh_gui(delay=0.0001, wait=0.0001):
    """Use up all the events waiting to be run

    :param delay: Time to wait before using events
    :param wait: Time to wait between iterations of events

    This function will block until all pending events are emitted. This is
    useful in testing to ensure signals and other asynchronous functionality
    is required to take place.

    (c) PyGTKHelpers Authors 2005-2010
    """
    time.sleep(delay)
    while gtk.events_pending():
        gtk.main_iteration_do(block=False)
        time.sleep(wait)

using block=False and some delays.

If you want to use threads, I personally wouldn't recommend subclassing Thread like that (there is no point), instead, I would advise an approach like this which has an example of updating a progress bar.

Ali A
Thanks for your reply, I'll try your advice later when I get home. I was nearly giving up all hope on trying to get it working.
Samuel Taylor