Comment créer la barre de progression du téléchargement dans ttk?

Je veux afficher une barre de progression lors du téléchargement d'un fichier à partir du web en utilisant la méthode urllib.urlretrive.

Comment utiliser le ttk.Progressbar pour effectuer cette tâche?

Voici ce que j'ai fait jusqu'à présent:

from tkinter import ttk
from tkinter import *

root = Tk()

pb = ttk.Progressbar(root, orient="horizontal", length=200, mode="determinate")
pb.pack()
pb.start()

root.mainloop()

Mais il continue à Boucler.

23
demandé sur nbro 2011-09-05 20:14:17

6 réponses

Pour le mode déterminé, vous ne voulez pas appeler start. Au lieu de cela, configurez simplement le value du widget ou appelez la méthode step.

Si vous savez à l'avance combien d'octets vous allez télécharger (et je suppose que vous le faites puisque vous utilisez le mode déterminé), la chose la plus simple à faire est de définir l'option maxvalue sur le nombre que vous allez lire. Ensuite, chaque fois que vous lisez un morceau de configurer le value pour le nombre total d'octets lus. La barre de progression va alors comprendre le pourcentage.

Voici une simulation pour vous donner une idée approximative:

import tkinter as tk
from tkinter import ttk


class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.button = ttk.Button(text="start", command=self.start)
        self.button.pack()
        self.progress = ttk.Progressbar(self, orient="horizontal",
                                        length=200, mode="determinate")
        self.progress.pack()

        self.bytes = 0
        self.maxbytes = 0

    def start(self):
        self.progress["value"] = 0
        self.maxbytes = 50000
        self.progress["maximum"] = 50000
        self.read_bytes()

    def read_bytes(self):
        '''simulate reading 500 bytes; update progress bar'''
        self.bytes += 500
        self.progress["value"] = self.bytes
        if self.bytes < self.maxbytes:
            # read more bytes after 100 ms
            self.after(100, self.read_bytes)

app = SampleApp()
app.mainloop()

Pour que cela fonctionne, vous devrez vous assurer que vous ne bloquez pas le thread GUI. Cela signifie que vous lisez en morceaux (comme dans l'exemple) ou faites la lecture dans un thread séparé. Si vous utilisez des threads, vous ne pourrez pas appeler directement les méthodes progressbar car tkinter est un thread unique.

, Vous trouverez peut-être la progressbar exemple sur tkdocs.com, pour être utile.

28
répondu Bryan Oakley 2015-12-21 04:32:53

, j'ai simplifié le code pour vous.

import sys
import ttk
from Tkinter import *

mGui = Tk()

mGui.geometry('450x450')
mGui.title('Hanix Downloader')

mpb = ttk.Progressbar(mGui,orient ="horizontal",length = 200, mode ="determinate")
mpb.pack()
mpb["maximum"] = 100
mpb["value"] = 50

mGui.mainloop()

Remplacer 50 avec le pourcentage de la télécharger.

7
répondu Ufoguy 2013-12-23 18:44:44

Si vous voulez juste une barre de progression pour montrer que le programme est occupé / fonctionne, changez simplement le mode de déterminé à indéterminé

pb = ttk.Progressbar(root,orient ="horizontal",length = 200, mode ="indeterminate")
3
répondu Simon Crouch 2012-10-31 11:26:51

Voici un autre exemple simple qui montre également une barre de progression en mouvement. (J'ai simplifié les exemples donnés à https://gist.github.com/kochie/9f0b60384ccc1ab434eb )

import Tkinter
import ttk

root = Tkinter.Tk()
pb = ttk.Progressbar(root, orient='horizontal', mode='determinate')
pb.pack(expand=True, fill=Tkinter.BOTH, side=Tkinter.TOP)
pb.start(50)
root.mainloop()
1
répondu Apostolos 2018-03-07 23:16:52

Fenêtre de dialogue modale avec Progressbar pour le projet plus grand

Cet exemple est un peu long, mais testé sur Python 3.6 et peut être utilisé dans le plus grand projet.

# -*- coding: utf-8 -*-
# Modal dialog window with Progressbar for the bigger project
import time
import tkinter as tk
from tkinter import ttk
from tkinter import simpledialog

class MainGUI(ttk.Frame):
    ''' Main GUI window '''
    def __init__(self, master):
        ''' Init main window '''
        ttk.Frame.__init__(self, master=master)
        self.master.title('Main GUI')
        self.master.geometry('300x200')
        self.lst = [
            'Bushes01.png',  'Bushes02.png', 'Bushes03.png', 'Bushes04.png', 'Bushes05.png',
            'Forest01.png',  'Forest02.png', 'Forest03.png', 'Forest04.png', 'Road01.png',
            'Road02.png',    'Road03.png',   'Lake01.png',   'Lake02.png',   'Field01.png']
        b = ttk.Button(self.master, text='Start', command=self.start_progress)
        b.pack()
        b.focus_set()

    def start_progress(self):
        ''' Open modal window '''
        s = ProgressWindow(self, 'MyTest', self.lst)  # create progress window
        self.master.wait_window(s)  # display the window and wait for it to close

class ProgressWindow(simpledialog.Dialog):
    def __init__(self, parent, name, lst):
        ''' Init progress window '''
        tk.Toplevel.__init__(self, master=parent)
        self.name = name
        self.lst = lst
        self.length = 400
        #
        self.create_window()
        self.create_widgets()

    def create_window(self):
        ''' Create progress window '''
        self.focus_set()  # set focus on the ProgressWindow
        self.grab_set()  # make a modal window, so all events go to the ProgressWindow
        self.transient(self.master)  # show only one window in the task bar
        #
        self.title(u'Calculate something for {}'.format(self.name))
        self.resizable(False, False)  # window is not resizable
        # self.close gets fired when the window is destroyed
        self.protocol(u'WM_DELETE_WINDOW', self.close)
        # Set proper position over the parent window
        dx = (self.master.master.winfo_width() >> 1) - (self.length >> 1)
        dy = (self.master.master.winfo_height() >> 1) - 50
        self.geometry(u'+{x}+{y}'.format(x = self.master.winfo_rootx() + dx,
                                         y = self.master.winfo_rooty() + dy))
        self.bind(u'<Escape>', self.close)  # cancel progress when <Escape> key is pressed

    def create_widgets(self):
        ''' Widgets for progress window are created here '''
        self.var1 = tk.StringVar()
        self.var2 = tk.StringVar()
        self.num = tk.IntVar()
        self.maximum = len(self.lst)
        self.tmp_str = ' / ' + str(self.maximum)
        #
        # pady=(0,5) means margin 5 pixels to bottom and 0 to top
        ttk.Label(self, textvariable=self.var1).pack(anchor='w', padx=2)
        self.progress = ttk.Progressbar(self, maximum=self.maximum, orient='horizontal',
                                        length=self.length, variable=self.num, mode='determinate')
        self.progress.pack(padx=2, pady=2)
        ttk.Label(self, textvariable=self.var2).pack(side='left', padx=2)
        ttk.Button(self, text='Cancel', command=self.close).pack(anchor='e', padx=1, pady=(0, 1))
        #
        self.next()

    def next(self):
        ''' Take next file from the list and do something with it '''
        n = self.num.get()
        self.do_something_with_file(n+1, self.lst[n])  # some useful operation
        self.var1.set('File name: ' + self.lst[n])
        n += 1
        self.var2.set(str(n) + self.tmp_str)
        self.num.set(n)
        if n < self.maximum:
            self.after(500, self.next)  # call itself after some time
        else:
            self.close()  # close window

    def do_something_with_file(self, number, name):
        print(number, name)

    def close(self, event=None):
        ''' Close progress window '''
        if self.progress['value'] == self.maximum:
            print('Ok: process finished successfully')
        else:
            print('Cancel: process is cancelled')
        self.master.focus_set()  # put focus back to the parent window
        self.destroy()  # destroy progress window

root = tk.Tk()
feedback = MainGUI(root)
root.mainloop()
0
répondu foo bar 2018-03-29 19:11:17

Je voudrais souligner quelque chose qui n'est pas apparent à partir de la simulation. Sur certains systèmes d'exploitation, os.stat() retournera 0 si un fichier vide a été ouvert pour l'écriture jusqu'à ce que le handle de fichier soit fermé. Cela va vaincre la capacité de la barre de progression montrant la taille de progression d'un fichier téléchargé.

-1
répondu coyot 2016-06-15 17:14:35