问题
I am trying to display downloaded images in tkinter Progressbar
, It is working but the progressbar finishes way before the all images are downloaded. I asked a very similar question tkinter updating progress bar on thread progress, My idea is to update progressbar depending on how many files were created using len(os.listdir('.'))
to count.
import tkinter
from tkinter.ttk import Progressbar
import os,uuid,requests,threading
import numpy as np
def bar():
temp = 0
for lst in chunks:
threads.append(threading.Thread(target=download_image, args=(lst)))
for x in threads:
x.start()
while temp<len(links):
progress['value'] = temp
root.update_idletasks()
temp =len(os.listdir('.'))
print("closing threads")
for i in threads:
i.join()
temp =len(os.listdir('.'))
progress['value'] = temp
print('done')
root.destroy()
with open('image_urls.txt','r') as f:
links = f.read().split('\n') #links to image urls
threads =[]
chunks = [i.tolist() for i in np.array_split(links, 10) if i.size>0]
root = tkinter.Tk()
root.geometry("400x300")
root.title('Downloader v1')
progress = Progressbar(root, orient = tkinter.HORIZONTAL,
length = 250, mode = 'determinate',maximum=len(links))
progress.pack(pady = 100)
notice = tkinter.Label(root, text=str(len(links)),
fg="grey2",)
notice.place(x=350, y=100)
compose_button = tkinter.Button(root, text = 'Start', command = bar)
compose_button.pack()
root.mainloop()
回答1:
Question: Tkinter
Progressbar
update from multipleThread
's
Core Point
.event_generate('<<Progressbar>>')
This example uses a virtual event '<<Progressbar>>'
to increment the Progressbar['value']
. This event driven progamming, needs, no callback, no polling .after
, no queue
, to work across Thread
's.
Imports:
import tkinter as tk
import tkinter.ttk as ttk
import threading, time
import random
The worker
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')
Customized
Progressbar
by inheriting fromttk.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
Usage:
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()
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6
来源:https://stackoverflow.com/questions/60670374/progressbar-finishes-before-set-maximum-amount