移动时Tkinter进度条/窗口无响应

时间:2011-02-01 21:12:49

标签: python progress-bar tkinter move

我从here借了一个进度条,我想用我的程序修改全局变量。以下是供参考的代码:

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()

这段代码和演示工作很棒,但是当我进行以下更改以便我可以测试我想如何将其添加到我的代码中时,进度窗口变得无响应并且每当我移动它或激活另一个窗口时都会变为空白。 / p>

##-------------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 个答案:

答案 0 :(得分:2)

some_fctother_fct都会每次睡眠10秒,因此应用程序在启动时会至少20秒没有响应,因为这些睡眠都会在调用mainloop之前发生。你是说在这20秒之后应用程序没有响应,或者你在问为什么它在前20秒没有响应?

Tkinter是单线程的,这意味着无论何时进入睡眠状态,它都无法在睡眠期间为事件提供服务。正是这种事件的服务定义了“响应性”。

答案 1 :(得分: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()