прогрессбар заканчивается до заданной максимальной суммы - PullRequest
0 голосов
/ 13 марта 2020

Я пытаюсь отобразить загруженные изображения в tkinter Progressbar, он работает, но индикатор выполнения завершает работу до того, как все изображения будут загружены. Я задал очень похожий вопрос tkinter Обновление индикатора выполнения на прогрессе потока , Моя идея - обновить индикатор выполнения в зависимости от того, сколько файлов было создано с использованием len(os.listdir('.')) для подсчета.

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 Ответ

2 голосов
/ 14 марта 2020

Вопрос : 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...