问题描述
我正在尝试在tkinter Progressbar
中显示下载的图像,它正在工作,但是进度条完成了所有图像的下载.我问了一个非常类似的问题 tkinter更新线程进度的进度条,我的想法是根据使用len(os.listdir('.'))
进行计数的文件数量来更新进度条.
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()
推荐答案
核心点
.event_generate('<<Progressbar>>')
此示例使用虚拟事件'<<Progressbar>>'
来增加Progressbar['value']
.此事件驱动的编程,不需要回调,无需轮询.after
,无需queue
即可跨Thread
进行工作.
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.
import tkinter as tk
import tkinter.ttk as ttk
import threading, time
import random
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')
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
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6
这篇关于进度栏在设置最大数量之前完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!