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

发布于 2024-10-15 12:17:00 字数 3824 浏览 6 评论 0原文

我从这里借用了一个进度条,我想用全局变量来调整我的程序中的工作。以下是供参考的代码:

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

知道这里发生了什么以及为什么它变得没有响应吗?它与所使用的全局变量有什么关系吗?当它不移动时,它似乎工作“正常”,但它绝对不一样。

I have borrowed a progress bar from here that I would like to adapt work in my program with global variables. Here is the code for reference:

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

This code and demo work great, but when I make the following changes so I can test how I would want to impliment it into my code, the progress window becomes unresponsive and turns blank whenever I move it or activate another window.

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

Any idea what is going on here and why it becomes unresponsive? Does it have anything to do with the global variable being used? It seems to work "ok" when it's not moved, but it's definitely not the same.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

仙气飘飘 2024-10-22 12:17:00

some_fctother_fct 均休眠 10 秒,因此应用在启动时将至少有 20 秒无响应,因为这些休眠均发生在 mainloop< 之前/code> 被调用。您是说即使在这 20 秒之后应用程序也没有响应,还是您在问为什么它在前 20 秒没有响应?

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

some_fct and other_fct both sleep for 10 seconds each, so the app will be unresponsive for at least 20 seconds when it starts up since those sleeps all happen before mainloop is called. Are you saying that even after those 20 seconds the app is unresponsive, or are you asking why it's unresponsive for the first 20 seconds?

Tkinter is single threaded, which means that any time you put in a sleep it's not going to be able to service events for the duration of the sleep. It is this servicing of events that defines "responsiveness".

勿忘初心 2024-10-22 12:17:00

这是我用来获得我想要的东西的代码:

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

Here is the code I used to get what I wanted:

##-------------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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文