【问题标题】:Python tkinter crashes often updating ProgressBar elementPython tkinter 崩溃经常更新 ProgressBar 元素
【发布时间】:2020-06-29 04:29:17
【问题描述】:

Windows 10 与 Python 2.7.13(32 位)

我有一个带有进度条的 Python tkinter 程序。程序执行一个长时间运行的操作,然后在重复之前等待一定的时间。

为了向用户提供反馈,当倒计时到下一个操作时,进度条会在确定模式下更新,然后在操作期间(持续时间未知)切换到不确定模式。

15-30 分钟后,在使用以下代码进行倒计时时,Windows 会弹出 python.exe 已停止工作 对话框,仅提供关闭程序的选项,并且程序无响应(大概是因为 Windows 已经停止了它)。

我无法弄清楚为什么会发生这种情况。在此期间,在 GUI 中运行以下代码段:

def wait_nextop(self, delay):
    end = time.time() + delay

    self.progress_bar.stop()
    self.progress_bar.config(mode = 'determinate', max = delay)

    while time.time() < end:
        remaining = (end - time.time()) + 1
        self.progress_bar.config(value = (delay - remaining))
        remaining_text = str(datetime.timedelta(seconds = int(remaining)))
        self.progress_text.config(text = 'Next operation in ' + remaining_text)
        time.sleep(0.1)

    self.progress_text.config(text = 'Operation in progress')    
    self.progress_bar.config(mode = 'indeterminate')
    self.progress_bar.start()

在此,delay 是以秒为单位的整数延迟。 self.progress_barttk.ProgressBar 的一个实例,self.progress_texttkinter.Label 的一个实例。 timedatetime 来自标准库。

Python 不提供堆栈跟踪,我目前没有其他系统可用于测试它。需要注意的是,这个 GUI 函数是由另一个线程调用的,但打算在主线程中执行。

我已经看到了这些类似的问题,但找不到有效的解决方案:

【问题讨论】:

  • 你不应该从创建小部件的线程以外的任何线程调用 tkinter 函数。
  • 遵循这种方法threaded Progressbar
  • @stovfl :您发布的方法似乎已经解决了问题,谢谢!我已经发布了一个使用该系统作为 Python 2.7 答案的工作示例,因为该示例似乎适用于 Python 3

标签: python multithreading python-2.7 tkinter


【解决方案1】:

根据 cmets 的建议,我似乎应该使用 tkinter 的事件系统,而不是直接在 GUI 线程中调用函数。

这是一个使用所描述概念的 Python2.7 工作示例。它创建带有进度条的 GUI,然后使用事件系统从另一个线程更新它。

## Import the required modules
import threading
import Tkinter as tk
import ttk
import time
import random

## Class for creating the GUI
class GUI():
    def __init__(self):
        ## Make the GUI
        self.root = tk.Tk()        
        self.progress = ttk.Progressbar(self.root, orient = 'horizontal', length = 100, mode = 'determinate', max = 10)

        ## Bind an event to trigger the update
        self.root.bind('<<MoveIt>>', self.update_progress)

        ## Pack the progress bar in to the GUI
        self.progress.pack()

    def run(self):
        ## Enter the main GUI loop. this blocks the main thread
        self.root.mainloop()

    ## Updates the progress bar
    def update_progress(self, event):
        ## Work out what the new value will be
        new_value = self.progress['value'] + 1

        ## If the new value is less than 10..
        if new_value < 10:
            print('[main thread] New progress bar value is ' + str(new_value))
            ## Update the progress bar value
            self.progress.config(value = new_value)
            ## Force the GUI to update
            self.root.update()
        ## If the new value is more than 10
        else:
            print('[main thread] Progress bar done. Exiting!')
            ## Exit the GUI (and terminate the script)
            self.root.destroy()

## Class for creating the worker thread
class Worker(threading.Thread):
    def __init__(self, ui):
        ## Run the __init__ function from our threading.Thread parent
        threading.Thread.__init__(self)

        ## Save a local reference to the GUI object
        self.ui = ui

        ## Set as a daemon so we don't block the program from exiting
        self.setDaemon(True)

    def run(self):        
        print('[new thread] starting')
        ## Count to 10
        for i in range(10):
            ## Generate an event to trigger the progress bar update
            ui.root.event_generate('<<MoveIt>>', when = 'tail')

            ## Wait between one and three seconds before doing it again
            wait = random.randint(1,3)
            print('[new thread] Incrementing progress bar again in ' + str(wait) + ' seconds')
            time.sleep(wait)

## Create an instance of the GUI class            
ui = GUI()
## Create an instance of the Worker class and tell it about the GUI object
work = Worker(ui)
## Start the worker thread
work.start()
## Start the GUI thread (blocking)
ui.run()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-17
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多