进度栏在设置最大数量之前完成 [英] progressbar finishes before set maximum amount

查看:92
本文介绍了进度栏在设置最大数量之前完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在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()

推荐答案

问题:Tkinter Progressbar从多个Thread

Question: Tkinter Progressbar update from multiple Thread's

核心点

    .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

工人Thread

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

通过继承ttk.Progressbar

Customized Progressbar by inheriting from 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

Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

这篇关于进度栏在设置最大数量之前完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆