Tkinter 进度条/窗口移动时无响应
我从这里借用了一个进度条,想把它调整一下,让它在我的程序中使用全局变量。以下是参考代码:
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 = 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 _demo(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, 'Starting demo...')
m.after(1000, lambda: _demo(m, 0.0))
root.mainloop()
这段代码和演示效果很好,但当我做了一些修改,想测试一下如何把它整合到我的代码中时,进度窗口变得无响应,而且每当我移动它或者激活其他窗口时,它就会变成空白。
##-------------demo code--------------------------------------------##
def some_fct(m):
global count
i = 0
while i < 5:
count = count + 1
sleep(2)
m.set(float(count) / total)
i = i + 1
def other_fct(m):
global count
i = 0
while i < 5:
count = count + 1
sleep(2)
m.set(float(count) / total)
i = i + 1
if __name__ == '__main__':
global count
global total
count = 0
total = 10
root = Tkinter.Tk(className='meter demo')
m = Meter(root, relief='ridge', bd=3)
m.pack(fill='x')
m.set(0.0, 'Starting meter')
some_fct(m)
other_fct(m)
root.mainloop()
你知道这是怎么回事吗?为什么它会变得无响应?这和使用全局变量有关吗?当它不被移动时,似乎“还行”,但肯定不是同样的效果。
2 个回答
2
some_fct
和 other_fct
都会各自暂停10秒,所以当应用程序启动时,至少会有20秒的时间是没有反应的,因为这些暂停都是在调用 mainloop
之前发生的。你是在问即使过了这20秒后,应用程序仍然没有反应,还是在问为什么前20秒没有反应呢?
Tkinter是单线程的,这意味着每当你让程序暂停时,它就无法处理其他事件,直到暂停结束。处理这些事件的能力就是我们说的“响应能力”。
2
这是我用来实现我想要的功能的代码:
##-------------demo code--------------------------------------------##
def count_numbers(number):
i = 0
while i < number:
i = i + 1
def some_fct():
global count
i = 0
while i < 5:
count = count + 1
count_numbers(5000000)
i = i + 1
def other_fct():
global count
i = 0
while i < 5:
count = count + 1
count_numbers(5000000)
i = i + 1
def do_stuff():
some_fct()
other_fct()
def update_progress(m):
value = float(count) / total
if value < 1.0:
m.set(value)
m.after(500, lambda: update_progress(m))
else:
m.set(value, 'Process Completed')
if __name__ == '__main__':
global count
global total
count = 0
total = 10
root = Tkinter.Tk(className='meter demo')
m = Meter(root, relief='ridge', bd=3)
m.pack(fill='x')
m.set(0.0, 'Starting meter')
m.after(50, lambda: update_progress(m))
thread.start_new_thread(do_stuff, () )
root.mainloop()