TTKでProgress Barをダウンロードする方法は?
質問
Webからファイルをダウンロードしている間に進行状況バーを表示したい urllib.urlretrive
方法。
どのように使用できますか ttk.Progressbar
このタスクを行うには?
これが私がこれまでに行ったことです:
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()
しかし、それはただループを続けます。
解決
決定的なモードの場合は、電話をかけたくありません start
. 。代わりに、単に構成します value
ウィジェットまたは電話をかけます step
方法。
ダウンロードするバイトの数を事前に知っている場合(そして、あなたが決定的なモードを使用しているのであなたがすると思います)、最も簡単なことは設定することです maxvalue
読み取る番号のオプション。その後、チャンクを読むたびに構成する value
読み取られるバイトの総数になること。その後、Progress Barはパーセンテージを把握します。
これがあなたに大まかなアイデアを与えるためのシミュレーションです:
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()
これが機能するには、GUIスレッドをブロックしないようにする必要があります。つまり、チャンクで(例のように)読むか、別のスレッドで読み取りを行うことを意味します。スレッドを使用する場合、TKINTERは単一のスレッドであるため、ProgressBarメソッドを直接呼び出すことができません。
あなたが見つけるかもしれません ProgressBarの例 の上 tkdocs.com 役に立つように。
他のヒント
私はあなたのためにコードを簡素化しました。
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()
交換 50 ダウンロードの割合。
プログラムが忙しいことを示すために進行状況バーが必要な場合/動作するだけで、モードを決定から不確定に変更するだけです
pb = ttk.Progressbar(root,orient ="horizontal",length = 200, mode ="indeterminate")
これも、進行状況の動きを示している別の簡単な例です。 (で与えられた例を簡素化しました https://gist.github.com/kochie/9f0b60384cc1ab434eb)
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()
より大きなプロジェクトのためのProgressBarを使用したモーダルダイアログウィンドウ
この例は少し長いですが、Python 3.6でテストされており、より大きなプロジェクトで使用できます。
# -*- 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()
シミュレーションから明らかではない何かを指摘したいと思います。一部のオペレーティングシステムでは、ファイルハンドルが閉じられるまで、書き込みのために空のファイルが開かれた場合、OS.Stat()が0を返します。これにより、ダウンロードされたファイルの進行状況を示す進行状況バーの能力が無効になります。