¿Cómo crear la barra de progreso de descarga en ttk?

Quiero mostrar una barra de progreso mientras descargo un archivo de la web usando el método urllib.urlretrive .

¿Cómo utilizo el ttk.Progressbar para hacer esta tarea?

Esto es lo que he hecho hasta ahora:

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

Pero simplemente sigue en bucle.

Para el modo determinado no desea start . En su lugar, simplemente configure el value del widget o llame al método de step .

Si sabe de antemano cuántos bytes va a descargar (y supongo que lo hace ya que está usando el modo determinado), lo más simple que puede hacer es establecer la opción de valor maxvalue en el número que va a leer. Luego, cada vez que lea un fragmento, configure el value para que sea el número total de bytes leídos. La barra de progreso luego calculará el porcentaje.

Aquí hay una simulación para darte una idea aproximada:

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

Para que esto funcione, necesitarás asegurarte de no bloquear el hilo de la GUI. Eso significa que puede leer en trozos (como en el ejemplo) o hacer la lectura en un hilo separado. Si utiliza subprocesos, no podrá llamar directamente a los métodos de la barra de progreso porque tkinter es un único subproceso.

Es posible que el ejemplo de la barra de progreso en tkdocs.com sea ​​útil.

Simplifiqué el código para ti.

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

Reemplace 50 con el porcentaje de la descarga.

Si solo desea que la barra de progreso muestre que el progtwig está ocupado / funcionando, simplemente cambie el modo de determinado a indeterminado

 pb = ttk.Progressbar(root,orient ="horizontal",length = 200, mode ="indeterminate") 

Aquí hay otro ejemplo simple que también muestra una barra de progreso en movimiento. (He simplificado los ejemplos dados en 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() 

Ventana de diálogo modal con barra de progreso para el proyecto más grande

Este ejemplo es un poco largo, pero probado en Python 3.6 y se puede utilizar en el proyecto más grande.

 # -*- 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'', self.close) # cancel progress when  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() 

Me gustaría señalar algo que no se ve en la simulación. En algunos sistemas operativos, os.stat () devolverá 0 si se abrió un archivo vacío para escribir hasta que se cierre el identificador de archivo. Esto anulará la capacidad de la barra de progreso que muestra el tamaño progresivo de un archivo descargado.