python - docs - ¿Cómo crear la barra de progreso de descarga en ttk?
ttk python (6)
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.
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()
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.
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 sabe 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 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.
Si solo desea que la barra de progreso muestre que el programa está ocupado / funcionando, simplemente cambie el modo de determinado a indeterminado
pb = ttk.Progressbar(root,orient ="horizontal",length = 200, mode ="indeterminate")
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.
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 puede usarse 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''<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()