2011-08-02 92 views
3

我有一個跟蹤運行上載進度的FTP函數,但我對線程的理解是有限的,我一直無法實現一個工作解決方案...我想添加一個GUI進度條通過使用線程來當前我的應用程序。有人可以使用異步線程顯示我的基本功能,可以從另一個正在運行的線程更新嗎?幫助爲GUI進程添加線程

def ftpUploader(): 
    BLOCKSIZE = 57344 # size 56 kB 

    ftp = ftplib.FTP() 
    ftp.connect(host) 
    ftp.login(login, passwd) 
    ftp.voidcmd("TYPE I") 
    f = open(zipname, 'rb') 
    datasock, esize = ftp.ntransfercmd(
     'STOR %s' % os.path.basename(zipname)) 
    size = os.stat(zipname)[6] 
    bytes_so_far = 0 
    print 'started' 
    while 1: 
     buf = f.read(BLOCKSIZE) 
     if not buf: 
      break 
     datasock.sendall(buf) 
     bytes_so_far += len(buf) 
     print "\rSent %d of %d bytes %.1f%%\r" % (
       bytes_so_far, size, 100 * bytes_so_far/size) 
     sys.stdout.flush() 

    datasock.close() 
    f.close() 
    ftp.voidresp() 
    ftp.quit() 
    print 'Complete...' 
+1

不要新線程使用GUI。爲單個線程保留所有GUI操作,並讓第二個線程完成FTP。 –

回答

1

這裏是線程的快速概覽,以防萬一:)我不會去太多的細節到GUI的東西,只是說,你應該看看wxWidgets的。當你做一些事情,需要很長的時間,如:

from time import sleep 
for i in range(5): 
    sleep(10) 

你會發現,給用戶,整個代碼塊似乎需要50秒。在這5秒鐘內,您的應用程序無法執行任何操作,例如更新界面,因此看起來它已凍結。爲了解決這個問題,我們使用線程。

通常這個問題有兩個部分;你想要處理的一整套事情,以及需要一段時間的操作,我們希望切碎。在這種情況下,整個集合是for循環,我們要切碎的操作是sleep(10)函數。

這是基於我們前面的示例的線程代碼的快速模板。你應該能夠將你的代碼加入到這個例子中。

from threading import Thread 
from time import sleep 

# Threading. 
# The amount of seconds to wait before checking for an unpause condition. 
# Sleeping is necessary because if we don't, we'll block the os and make the 
# program look like it's frozen. 
PAUSE_SLEEP = 5 

# The number of iterations we want. 
TOTAL_ITERATIONS = 5 

class myThread(Thread): 
    ''' 
    A thread used to do some stuff. 
    ''' 
    def __init__(self, gui, otherStuff): 
     ''' 
     Constructor. We pass in a reference to the GUI object we want 
     to update here, as well as any other variables we want this 
     thread to be aware of. 
     ''' 
     # Construct the parent instance. 
     Thread.__init__(self) 

     # Store the gui, so that we can update it later. 
     self.gui = gui 

     # Store any other variables we want this thread to have access to. 
     self.myStuff = otherStuff 

     # Tracks the paused and stopped states of the thread. 
     self.isPaused = False 
     self.isStopped = False 

    def pause(self): 
     ''' 
     Called to pause the thread. 
     ''' 
     self.isPaused = True 

    def unpause(self): 
     ''' 
     Called to unpause the thread. 
     ''' 
     self.isPaused = False 

    def stop(self): 
     ''' 
     Called to stop the thread. 
     ''' 
     self.isStopped = True 

    def run(self): 
     ''' 
     The main thread code. 
     ''' 
     # The current iteration. 
     currentIteration = 0 

     # Keep going if the job is active. 
     while self.isStopped == False: 
      try: 
       # Check for a pause. 
       if self.isPaused: 
        # Sleep to let the os schedule other tasks. 
        sleep(PAUSE_SLEEP) 
        # Continue with the loop. 
        continue 

       # Check to see if we're still processing the set of 
       # things we want to do. 
       if currentIteration < TOTAL_ITERATIONS: 
        # Do the individual thing we want to do. 
        sleep(10) 
        # Update the count. 
        currentIteration += 1 
        # Update the gui. 
        self.gui.update(currentIteration,TOTAL_ITERATIONS) 
       else: 
        # Stop the loop. 
        self.isStopped = True 

      except Exception as exception: 
       # If anything bad happens, report the error. It won't 
       # get written to stderr. 
       print exception 
       # Stop the loop. 
       self.isStopped = True 

     # Tell the gui we're done. 
     self.gui.stop() 

要調用這個主題,所有你需要做的是:

aThread = myThread(myGui,myOtherStuff) 
aThread.start() 
+0

我能夠使用提供的示例插入和運行我的代碼,但我仍然不知道如何更新主窗口...如何將狀態傳遞迴原始GUI實例? BTY:使用wxPython的Im .. – Simpleton

+0

當你構建你的線程時,將窗口作爲參數傳遞給線程並在本地存儲窗口。這是self.gui。然後當你完成後,你可以在主線程上調用一個方法來更新它。 –