我正在尝试将 https://stackoverflow.com/a/75728288/7611214 的 ctk 进度条组合到像 https://stackoverflow.com/a/325528/7611214 这样可停止的线程上。我想我已经很接近了,但我只是不能完全把它整合在一起。有人可以帮助我完成我的代码,以便在这种情况下,在线程 5 秒后中断之前,栏会前进一定的距离(类似于有人点击取消按钮)?
import customtkinter as ctk
import threading
import time
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
class App(ctk.CTk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.Progress_Bar = (ctk.CTkProgressBar(master=self, height=15, width=150, mode='determinate'))
self.Progress_Bar.place(x=10, y=10)
self.Progress_Bar.set(0)
self.update()
my_thread = Algorithm()
my_thread.start()
time.sleep(5)
my_thread.stop()
class Algorithm(StoppableThread):
def test(self):
n = 50
iter_step = 1 / n
progress_step = iter_step
self.Progress_Bar.start()
while not self.stopped():
for x in range(n):
self.Progress_Bar.set(progress_step)
progress_step += iter_step
self.Progress_Bar.set(progress_step)
self.update_idletasks()
self.Progress_Bar.stop()
app = App()
app.mainloop()
不幸的是,对此没有简单的解决方案,您的函数需要了解它们正在运行的线程。您提供的线程类可以像这样使用:
import tkinter as tk
from tkinter import ttk
import threading
import time
from functools import partial
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
root = tk.Tk()
progress = ttk.Progressbar(root, orient = 'horizontal', length = 100, mode = 'determinate')
def foo(thread, stop_after=None):
start = time.time()
# Main computation loop
for i in range(20):
if (stop_after is not None) and (time.time()-start > stop_after):
thread.stop()
if (thread.stopped()):
break
progress['value'] = (i+1)*5
root.update_idletasks()
time.sleep(0.1)
# Resource cleanup or logging
print(f"stopped after {time.time()-start} seconds")
progress.pack(pady = 10)
thread = StoppableThread()
# This button will initialize
# the progress bar
ttk.Button(root, text = 'Start', command = partial(foo,thread,1)).pack(pady = 10)
# infinite loop
root.mainloop()
但关键的要点是该函数需要检查线程的状态以中止其正在执行的任何操作。如果您使用一次处理一项的生成器,那么这会变得更容易处理;您可以使用以下方法,而不是尝试打破循环:
while not thread.stopped():
和 next(YOUR_GENERATOR)
一次做一个您想做的事。
当我在 tkinter 中编写 GUI 时,我通常有一个线程管理器,用于根据池中的计算状态动态更新按钮以执行进程或中止进程。