Python tkinter在更新ProgressBar元素时经常崩溃



带有Python 2.7.13(32位(的Windows 10

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

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

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

在这种情况下,延迟是以秒为单位的整数延迟self.progress_barttk的一个实例。ProgressBarself。progress_texttkinter的一个实例。标签time

datetimePython不提供堆栈跟踪,我目前也没有其他系统可以对此进行测试。需要注意的是,这个GUI函数是由另一个线程调用的,但旨在在主线程中执行。

我见过这些类似的问题,但找不到一个有效的解决方案:

  • Python tkinter代码停止工作
  • Tkinter python在试图登录主线程的新线程上崩溃

根据评论中的建议,我似乎应该使用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()

最新更新