python:tkinter/urllib/requests - 运行 下载命令时 GUI 无响应
python: tkinter/urllib/requests - GUI not responding when running download command
我尝试制作一个 GUI,其中有一个下载按钮,它可以从 Internet 下载文件。
还有一个进度条显示下载进度..
完整代码:
#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()
但是当我点击下载按钮时,整个 window 停止响应..
一段时间后,当下载完成时,它会响应..并且进度条变为 100% 完成..
试试这个:
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()
首先,您的代码有一些错误:
- 您继续以
"wb"
模式打开文件,这会覆盖您下载的最后一个块。
- 你无缘无故把尺寸除以1024
- 另外你下载的文件很小。无需迭代其内容。上面的代码假设你有一个大文件
我做过的事情:
- 我添加了一个
tkinter
循环,它使用全局变量与新线程通信。
- 该线程下载文件。
- 我还将 url 更改为一个大文件 (> 1GB) 只是为了检查它是否正常工作。
- 我也更改了它,所以它只打开文件一次,这样我们就可以保存整个文件
我尝试制作一个 GUI,其中有一个下载按钮,它可以从 Internet 下载文件。 还有一个进度条显示下载进度..
完整代码:
#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()
但是当我点击下载按钮时,整个 window 停止响应.. 一段时间后,当下载完成时,它会响应..并且进度条变为 100% 完成..
试试这个:
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()
首先,您的代码有一些错误:
- 您继续以
"wb"
模式打开文件,这会覆盖您下载的最后一个块。 - 你无缘无故把尺寸除以1024
- 另外你下载的文件很小。无需迭代其内容。上面的代码假设你有一个大文件
我做过的事情:
- 我添加了一个
tkinter
循环,它使用全局变量与新线程通信。 - 该线程下载文件。
- 我还将 url 更改为一个大文件 (> 1GB) 只是为了检查它是否正常工作。
- 我也更改了它,所以它只打开文件一次,这样我们就可以保存整个文件