Индикатор выполнения / окно Tkinter не отвечает при перемещении - PullRequest
0 голосов
/ 02 февраля 2011

Я позаимствовал индикатор прогресса из здесь , который я хотел бы адаптировать в своей программе для работы с глобальными переменными.Вот код для справки:

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 голосов
/ 02 февраля 2011

Вот код, который я использовал, чтобы получить то, что я хотел:

##-------------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()
2 голосов
/ 02 февраля 2011

some_fct и other_fct оба спят по 10 секунд каждый, поэтому приложение не будет реагировать по крайней мере на 20 секунд при запуске, так как все эти спящие происходят до вызова mainloop.Вы говорите, что даже после этих 20 секунд приложение не отвечает или вы спрашиваете, почему оно не отвечает в течение первых 20 секунд?

Tkinter является однопоточным, что означает, что каждый раз, когда вы засыпаете, оно несобирается быть в состоянии обслуживать события на время сна.Именно это обслуживание событий определяет «отзывчивость».

...