I tried making a GUI where there is a download button and it downloads a file from the internet. There is also a progressbar which shows progress of the download..
the whole code:
#minimal reproductive example.. import os import time import yaml import urllib import requests import tempfile import tkinter as tk from tkinter import ttk from tkinter import * TEMP = tempfile.gettempdir() def download(progressbar=None): start = time.time() url = 'https://proget.whirlpool.repl.co/information.yml' local_filename = TEMP+"\"+url.split('/')[-1] url_file = urllib.request.urlopen(url) size= url_file.headers["Content-Length"] print("Starting to download file", end = "r") if progressbar: progressbar['maximum'] = int(int(size)/1024) with requests.get(url, stream=True) as r: r.raise_for_status() with open(local_filename, 'wb') as f: sz = 0 for chunk in r.iter_content(chunk_size=8192): f.write(chunk) sz = sz+8192 if progressbar: progressbar['value'] = progressbar['value'] + 8192 os.system(local_filename) def Download(*args): download(progressbar=pb95) root = tk.Tk() style = ttk.Style(root) pb95 = ttk.Progressbar(root,orient='horizontal', mode='determinate',length=500, maximum=1) pb95.pack(side='top',fill='y') downloadbtn = tk.Button(root,text='Download',font='Consolas 30', bg='green', fg='white',relief='flat', command=Download) downloadbtn.pack(side='bottom',fill='x') root.mainloop()
but when i click on the download button, the whole window stops responding.. and after some time, when the download is finished, it responds.. and the progressbar becomes 100% done..
Advertisement
Answer
Try this:
import urllib import requests from tkinter import ttk import tkinter as tk # Import threading from threading import Thread def download(progressbar=None): global progress_value, progress_maximum, progress_done progress_value = 0 url = 'https://proget.whirlpool.repl.co/information.yml' # I hard coded a large file for testing url = "https://mirror.bytemark.co.uk/ubuntu-releases/21.04/ubuntu-21.04-desktop-amd64.iso" # I also hard coded in a temp folder for testing local_filename = "tmp/"+url.split('/')[-1] url_file = urllib.request.urlopen(url) size= url_file.headers["Content-Length"] print("Starting to download file") # If you want running the file to take 50% of the progressbar uncomment the `*2` progress_maximum = int(size) # *2 file = open(local_filename, "wb") with requests.get(url, stream=True) as r: r.raise_for_status() for chunk in r.iter_content(chunk_size=8192): file.write(chunk) progress_value += len(chunk) file.close() print("Running the file") # os.system(local_filename) print("Done") progress_value = progress_maximum progress_done = True def Download(*args): # Add a default value for the value of the progress bar: global progress_value, progress_maximum, progress_done progress_value = 0 progress_maximum = 1 progress_done = False # Start the new thread new_thread = Thread(target=download, daemon=True) new_thread.start() # Start the tkinter loop: root.after(100, tkinter_download_loop) def tkinter_download_loop(): pb95["maximum"] = progress_maximum pb95["value"] = progress_value # After 100 ms call `tkinter_download_loop` again if not progress_done: root.after(100, tkinter_download_loop) root = tk.Tk() pb95 = ttk.Progressbar(root, orient="horizontal", length=500) pb95.pack(side="top", fill="y") downloadbtn = tk.Button(root, text="Download", command=Download) downloadbtn.pack(side="bottom", fill="x") root.mainloop()
First of all, your code had a few mistakes:
- You keep opening the file in
"wb"
mode, which overrides the last chunk that you downloaded. - You divide the size by 1024 for no reason.
- Also the file you are downloading is very small. There is no need to iterate over it’s contents. The code above assumes that you have a large file
Things I did:
- I added a
tkinter
loop that uses global variables to communicate with a new thread. - That thread downloads the file.
- I also changed the url to a large file (> 1GB) just to check that it’s working properly.
- I also changed it so it opens the file only once so we can save the full file