2010-09-09 60 views
3

我有提取tar.gz文件,同時保持對進度選項卡下面的代碼:爲什麼tkinter進度條讓事情變得如此慢?

from __future__ import division 
import tarfile 
import os 

theArchive = "/Users/Dennis/Instances/atlassian-jira-enterprise-4.1.2-standalone.tar.gz" 

a = tarfile.open(theArchive) 

tarsize = 0 

print "Computing total size" 
for tarinfo in a: 
    tarsize = tarsize + tarinfo.size 

realz = tarsize 
print "compressed size: " + str(a.fileobj.size) 
print "uncompressed size: " + str(tarsize) 

tarsize = 0 

for tarinfo in a: 
    print tarinfo.name, "is", tarinfo.size, "bytes in size and is", 
    if tarinfo.isreg(): 
     print "a regular file." 
    elif tarinfo.isdir(): 
     print "a directory." 
    else: 
     print "something else." 
    a.extract(tarinfo) 
    tarsize = tarsize + tarinfo.size 
    print str(tarsize) + "/" + str(realz) 
    outout = tarsize/realz 
    print "progress: " + str(outout) 

a.close() 

這是相當迅速,在提取10秒一個100MB的tar.gz。我想有這種視覺上也讓我改變了這包括Tkinter的進度條:

from __future__ import division 
import tarfile 
import os 
import Tkinter 

class Meter(Tkinter.Frame): 
    def __init__(self, master, width=300, height=20, bg='white', fillcolor='orchid1',\ 
       value=0.0, text=None, font=None, textcolor='black', *args, **kw): 
     Tkinter.Frame.__init__(self, master, bg=bg, width=width, height=height, *args, **kw) 
     self._value = value 

     self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ 
            highlightthickness=0, relief='flat', bd=0) 
     self._canv.pack(fill='both', expand=1) 
     self._rect = self._canv.create_rectangle(0, 0, 0, self._canv.winfo_reqheight(), fill=fillcolor,\ 
               width=0) 
     self._text = self._canv.create_text(self._canv.winfo_reqwidth()/2, self._canv.winfo_reqheight()/2,\ 
              text='', fill=textcolor) 
     if font: 
      self._canv.itemconfigure(self._text, font=font) 

     self.set(value, text) 
     self.bind('<Configure>', self._update_coords) 

    def _update_coords(self, event): 
     '''Updates the position of the text and rectangle inside the canvas when the size of 
     the widget gets changed.''' 
     # looks like we have to call update_idletasks() twice to make sure 
     # to get the results we expect 
     self._canv.update_idletasks() 
     self._canv.coords(self._text, self._canv.winfo_width()/2, self._canv.winfo_height()/2) 
     self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*self._value, self._canv.winfo_height()) 
     self._canv.update_idletasks() 

    def get(self): 
     return self._value, self._canv.itemcget(self._text, 'text') 

    def set(self, value=0.0, text=None): 
     #make the value failsafe: 
     if value < 0.0: 
      value = 0.0 
     elif value > 1.0: 
      value = 1.0 
     self._value = value 
     if text == None: 
      #if no text is specified use the default percentage string: 
      text = "Extraction: " + str(int(round(100 * value))) + ' %' 
     self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*value, self._canv.winfo_height()) 
     self._canv.itemconfigure(self._text, text=text) 
     self._canv.update_idletasks() 

##-------------demo code--------------------------------------------## 

def _goExtract(meter, value): 
    meter.set(value) 
    if value < 1.0: 
     value = value + 0.005 
     meter.after(50, lambda: _demo(meter, value)) 
    else: 
     meter.set(value, 'Demo successfully finished') 

if __name__ == '__main__': 
    root = Tkinter.Tk(className='meter demo') 
    m = Meter(root, relief='ridge', bd=3) 
    m.pack(fill='x') 
    m.set(0.0, 'Computing file size...') 
    m.after(1000) 

    theArchive = "/Users/Dennis/Instances/atlassian-jira-enterprise-4.1.2-standalone.tar.gz" 

    a = tarfile.open(theArchive) 

    tarsize = 0 

    for tarinfo in a: 
     tarsize = tarsize + tarinfo.size 

    realz = tarsize 
    print "real size: " + str(tarsize) 
    print "compressed size: " + str(a.fileobj.size) 

    m.set(0.0, 'Done computing!') 
    m.after(1000) 

    tarsize = 0 

    for tarinfo in a: 
     print tarinfo.name, "is", tarinfo.size, "bytes in size and is", 
     if tarinfo.isreg(): 
      print "a regular file." 
     elif tarinfo.isdir(): 
      print "a directory." 
     else: 
      print "something else." 
     a.extract(tarinfo) 
     tarsize = tarsize + tarinfo.size 
     print str(tarsize) + "/" + str(realz) 
     outout = tarsize/realz 
     m.set(outout) 
     print "progress: " + str(outout) 

    a.close() 

    m.set(1.0, 'Extraction complete!') 
    m.after(1000) 
    m.after(1000, lambda: _goExtract(m, 0.0)) 

它的工作原理都非常愉快,但進程現在需要超過分鐘。爲什麼會發生這種情況,我該如何解決這個問題?

謝謝!

Dennis

回答

5

存檔中的文件有多大?幾乎可以肯定地更新進度條的次數遠遠超過您的需要 - 通常在您的set()函數中包含一個支票,以便它只是在沒有更新的情況下返回,如果上次值的更改太小。對於300px的畫布,更新不超過0.3%的變化是毫無意義的,更新頻率可能不會超過每1%。

由於您的過程通常在10秒內完成,您可能還需要引入基於時間的檢查,因爲即使每1%更新一次也會每秒更新10次,這比您需要的次數要多。如果您從簡單的for循環中驅動它,看看Tk花費多少時間來繪製條形圖會很有趣。

+0

一個簡單的循環也會變慢,因爲它也會每0.1%迭代一次。對於如何不定期更新進度欄,您有任何建議嗎?比如每1%或2%? – FLX 2010-09-10 07:18:57

+0

嗨安德魯,從頭開始,現在我通過四捨五入的進度值,並在迭代之間放置一個if子句來檢查進度是否增加,從而充分發揮作用。現在它只是在更新進度的0.01%的地方進行更新,現在非常快速:) – FLX 2010-09-10 11:43:38

+0

很高興你的工作:)。 – 2010-09-10 14:02:01