請運行以下示例。Python Tkinter:使用多線程時進度條出現故障
我爲我的應用程序創建了一個進度條,並通過按下「打開」按鈕彈出一個進度條。但是,進度條不填滿,看來該腳本是在停止
bar.set(i)
時功能ProgressBarLoop被調用。
from Tkinter import Tk, Frame, BOTH, Label, Toplevel, Canvas, Button
import thread
import time
class ProgressBar:
def __init__(self, parent, width, height):
master = Toplevel(parent)
master.protocol('WM_DELETE_WINDOW', self.hide)
self.master = master
self.master.overrideredirect(True)
ws = self.master.winfo_screenwidth()
hs = self.master.winfo_screenheight()
w = (True and ws*0.2) or 0.2
h = (True and ws*0.15) or 0.15
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
self.master.geometry('%dx%d+%d+%d' % (width, height * 2.5, x, y))
self.mode = 'percent'
self.ONOFF = 'on'
self.width = width
self.height = height
self.frame = None
self.canvas = None
self.progressBar = None
self.backgroundBar = None
self.progressformat = 'percent'
self.label = None
self.progress = 0
self.createWidget()
self.frame.pack()
self.set(0.0) # initialize to 0%
def createWidget(self):
self.frame = Frame(self.master, borderwidth = 1, relief = 'sunken')
self.canvas = Canvas(self.frame)
self.backgroundBar = self.canvas.create_rectangle(0, 0, self.width, self.height, fill = 'darkblue')
self.progressBar = self.canvas.create_rectangle(0, 0, self.width, self.height, fill = 'blue')
self.setWidth()
self.setHeight()
self.label = Label(self.frame, text = 'Loading...', width = 20)
self.label.pack(side = 'top') # where text label should be packed
self.canvas.pack()
def setWidth(self, width = None):
if width is not None:
self.width = width
self.canvas.configure(width = self.width)
self.canvas.coords(self.backgroundBar, 0, 0, self.width, self.height)
self.setBar() # update progress bar
def setHeight(self, height = None):
if height is not None:
self.height = height
self.canvas.configure(height = self.height)
self.canvas.coords(self.backgroundBar, 0, 0, self.width, self.height)
self.setBar() # update progress bar
def set(self, value):
if self.ONOFF == 'off': # no need to set and redraw if hidden
return
if self.mode == 'percent':
self.progress = value
self.setBar()
return
def setBar(self):
self.canvas.coords(self.progressBar,0, 0, self.width * self.progress/100.0, self.height)
self.canvas.update_idletasks()
def hide(self):
if isinstance(self.master, Toplevel):
self.master.withdraw()
else:
self.frame.forget()
self.ONOFF = 'off'
def configure(self, **kw):
mode = None
for key,value in kw.items():
if key=='mode':
mode = value
elif key=='progressformat':
self.progressformat = value
if mode:
self.mode = mode
def ProgressBarLoop(window, bar):
bar.configure(mode = 'percent', progressformat = 'ratio')
while(True):
if not window.loading:
break
for i in range(101):
bar.set(i)
print "refreshed bar"
time.sleep(0.001)
bar.hide()
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.pack(fill = BOTH, expand = True)
parent.geometry('%dx%d+%d+%d' % (100, 100, 0, 0))
Button(parent, text = "Open", command = self.onOpen).pack()
def onOpen(self, event = None):
self.loading = True
bar = ProgressBar(self, width=150, height=18)
thread.start_new_thread(ProgressBarLoop, (self, bar))
while(True):
pass
root = Tk()
Application(root)
root.mainloop()
編輯:
試圖端午的回答後,它的工作原理,但我得到了以下錯誤:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/mnt/sdev/tools/lib/python2.7/threading.py", line 551, in __bootstrap_inner
self.run()
File "/mnt/sdev/tools/lib/python2.7/threading.py", line 504, in run
self.__target(*self.__args, **self.__kwargs)
File "/home/jun/eclipse/connScript/src/root/nested/test.py", line 88, in ProgressBarLoop
bar.set(i)
File "/home/jun/eclipse/connScript/src/root/nested/test.py", line 61, in set
self.setBar()
File "/home/jun/eclipse/connScript/src/root/nested/test.py", line 64, in setBar
self.canvas.coords(self.progressBar,0, 0, self.width * self.progress/100.0, self.height)
File "/mnt/sdev/tools/lib/python2.7/lib-tk/Tkinter.py", line 2178, in coords
self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop
嗯,我得到一個錯誤,當我關閉窗口RuntimeError:主線程不在主循環中 – 2014-09-26 18:30:42
@JamestheGreat你運行上面包含的確切示例代碼,除了我的'onOpen'方法嗎?我一直無法重現該錯誤。在線程中使用'Tk'在安全方面有點棘手,但只要你的主線程在'root.mainloop()'中,它就會預期它的行爲正常。 – dano 2014-09-26 18:53:25
我在Python 2.7和Linux上運行。 – 2014-09-26 19:19:50