Вопрос : Tkinter Progressbar
обновление с нескольких Thread
Core Point
.event_generate('<<Progressbar>>')
В этом примере виртуальное событие '<<Progressbar>>'
используется для увеличения Progressbar['value']
. Это управляемое событиями прогаммирование , требует, без обратного вызова, без опроса .after
, без queue
, для работы через Thread
.
Импорт :
import tkinter as tk
import tkinter.ttk as ttk
import threading, time
import random
Рабочий Thread
class Task(threading.Thread):
is_alive = 0
def __init__(self, app, args, name):
super().__init__(name=name, daemon=True)
self.args = args[0]
self.app = app
self._lock = threading.Lock()
self.start()
def run(self):
# threaded task
with self._lock:
Task.is_alive += 1
time.sleep(0.01)
for link in self.args:
print('Thread[{}]: link:{}'.format(self.name, link))
time.sleep(random.randint(1, 5))
with self._lock:
self.app.event_generate('<<Progressbar>>', when='tail')
# on end of threaded task
with self._lock:
Task.is_alive -= 1
if Task.is_alive == 0:
# last Task has finished
self.app.event_generate('<<COMPLETED>>', when='tail')
Настраивается Progressbar
путем наследования от ttk.Progressbar
class Progressbar(ttk.Progressbar):
def __init__(self, parent):
super().__init__(parent, orient="horizontal",
maximum=0, mode="determinate", length=250)
parent.bind('<<Progressbar>>', self.value)
def value(self, event):
self['value'] += 1
Использование :
class App(tk.Tk):
def __init__(self):
super().__init__()
self.pb = Progressbar(self)
self.pb.pack()
tk.Button(self, text="Start", command=self.start).pack()
self.bind('<<COMPLETED>>', self.on_completed)
def start(self):
links = (1, 2, 3, 4, 5, 6, 7, 8, 9)
self.pb['maximum'] = len(links)
chunks = [l for l in zip(links[0::3], links[1::3], links[2::3])]
for i, args in enumerate(chunks, 1):
# Task start() at once
Task(self, name='Task {}'.format(i), args=(args,))
def on_completed(self, event):
# Do cleanups before exiting
self.destroy()
if __name__ == "__main__":
App().mainloop()
Протестировано с Python: 3,5 - «TclVersion»: 8,6 «TkVersion»: 8,6