如何在 tkinter 中显示加载消息
how to show a loading message in tkinter
我是 tkinter 新手。我制作了所需的对话框。我的一个功能需要一些时间来处理。所以我想在该函数开始执行之前显示 "loading ... " 消息。
b1 = Button(text = "Compare",command = compare)
b1.pack()
单击此按钮时,compare() 函数开始执行。我想在该功能启动之前显示一条加载消息。我尝试使用标签,以便在 compare() 函数开始时为其设置一个值。但只有在函数执行完毕后才会生效。
我该怎么做?请帮助我..
看看manual for widgets。 w.wait_visibility(window)
等到小部件可见。 'normal' 事情的方式(在所有 GUI 工具包中)是将所有绘图命令(例如您的标签)放在等待列表中,并在有时间时进行实际绘图,优先考虑其他事件)。来自页面:
Wait for the given widget to become visible. This is typically used to wait until a new toplevel window appears on the screen. Like
wait_variable, this method enters a local event loop, so other parts
of the application will still work as usual.
使用 wait_visibility
的示例来自 test_widgets.py 代码,其中设置等待小部件真正显示:
class WidgetTest(unittest.TestCase):
"""Tests methods available in every ttk widget."""
def setUp(self):
support.root_deiconify()
self.widget = ttk.Button(width=0, text="Text")
self.widget.pack()
self.widget.wait_visibility()
当然,compare
功能确实需要一些可观的时间 - 否则标签可能会在屏幕上实际看到之前消失。您的屏幕每秒重绘 60 次,因此如果比较时间少于 16 毫秒,您可能什么也看不到。
编辑:更好的方法实际上是使用 update_idletasks
。这是一些代码:
import tkinter as tk
import time
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack(side="top", fill = "both", expand=True)
self.label = tk.Label(self, text = "Hello, world")
button1 = tk.Button(self, text = "Start to do something",
command = self.do_something)
self.label.pack(in_=self.frame)
button1.pack(in_=self.frame)
def do_something(self):
self.label.config(text = "Wait till I'm done...")
self.label.update_idletasks()
time.sleep(2)
print ("end sleep")
self.label.config(text = "I'm done doing...")
def main():
app = SampleApp()
app.mainloop()
return 0
if __name__ == '__main__':
main()
do_something
中的time.sleep
模拟你想做的任何事情。单击按钮开始该过程。
只要给定的函数是 运行。
,这将使带有不确定进度条的弹出窗口与给定的消息一起出现
from tkinter import *
import tkinter.ttk as ttk
import threading
# the given message with a bouncing progress bar will appear for as long as func is running, returns same as if func was run normally
# a pb_length of None will result in the progress bar filling the window whose width is set by the length of msg
# Ex: run_func_with_loading_popup(lambda: task('joe'), photo_img)
def run_func_with_loading_popup(func, msg, window_title = None, bounce_speed = 8, pb_length = None):
func_return_l = []
class Main_Frame(object):
def __init__(self, top, window_title, bounce_speed, pb_length):
print('top of Main_Frame')
self.func = func
# save root reference
self.top = top
# set title bar
self.top.title(window_title)
self.bounce_speed = bounce_speed
self.pb_length = pb_length
self.msg_lbl = Label(top, text=msg)
self.msg_lbl.pack(padx = 10, pady = 5)
# the progress bar will be referenced in the "bar handling" and "work" threads
self.load_bar = ttk.Progressbar(top)
self.load_bar.pack(padx = 10, pady = (0,10))
self.bar_init()
def bar_init(self):
# first layer of isolation, note var being passed along to the self.start_bar function
# target is the function being started on a new thread, so the "bar handler" thread
self.start_bar_thread = threading.Thread(target=self.start_bar, args=())
# start the bar handling thread
self.start_bar_thread.start()
def start_bar(self):
# the load_bar needs to be configured for indeterminate amount of bouncing
self.load_bar.config(mode='indeterminate', maximum=100, value=0, length = self.pb_length)
# 8 here is for speed of bounce
self.load_bar.start(self.bounce_speed)
# self.load_bar.start(8)
self.work_thread = threading.Thread(target=self.work_task, args=())
self.work_thread.start()
# close the work thread
self.work_thread.join()
self.top.destroy()
# # stop the indeterminate bouncing
# self.load_bar.stop()
# # reconfigure the bar so it appears reset
# self.load_bar.config(value=0, maximum=0)
def work_task(self):
func_return_l.append(func())
# create root window
root = Tk()
# call Main_Frame class with reference to root as top
Main_Frame(root, window_title, bounce_speed, pb_length)
root.mainloop()
return func_return_l[0]
if __name__ == '__main__':
import time
def task(i):
# The window will stay open until this function call ends.
for x in range(10):
print('hi: ' + i)
time.sleep(.5) # Replace this with the code you want to run
return "this is the func return"
msg = 'running func...'
bounc_speed = 9
pb_length = 200
window_title = "Wait"
r = run_func_with_loading_popup(lambda: task('joe'), msg, window_title, bounc_speed, pb_length)
print('return of test: ', r)
我是 tkinter 新手。我制作了所需的对话框。我的一个功能需要一些时间来处理。所以我想在该函数开始执行之前显示 "loading ... " 消息。
b1 = Button(text = "Compare",command = compare)
b1.pack()
单击此按钮时,compare() 函数开始执行。我想在该功能启动之前显示一条加载消息。我尝试使用标签,以便在 compare() 函数开始时为其设置一个值。但只有在函数执行完毕后才会生效。
我该怎么做?请帮助我..
看看manual for widgets。 w.wait_visibility(window)
等到小部件可见。 'normal' 事情的方式(在所有 GUI 工具包中)是将所有绘图命令(例如您的标签)放在等待列表中,并在有时间时进行实际绘图,优先考虑其他事件)。来自页面:
Wait for the given widget to become visible. This is typically used to wait until a new toplevel window appears on the screen. Like wait_variable, this method enters a local event loop, so other parts of the application will still work as usual.
使用 wait_visibility
的示例来自 test_widgets.py 代码,其中设置等待小部件真正显示:
class WidgetTest(unittest.TestCase):
"""Tests methods available in every ttk widget."""
def setUp(self):
support.root_deiconify()
self.widget = ttk.Button(width=0, text="Text")
self.widget.pack()
self.widget.wait_visibility()
当然,compare
功能确实需要一些可观的时间 - 否则标签可能会在屏幕上实际看到之前消失。您的屏幕每秒重绘 60 次,因此如果比较时间少于 16 毫秒,您可能什么也看不到。
编辑:更好的方法实际上是使用 update_idletasks
。这是一些代码:
import tkinter as tk
import time
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack(side="top", fill = "both", expand=True)
self.label = tk.Label(self, text = "Hello, world")
button1 = tk.Button(self, text = "Start to do something",
command = self.do_something)
self.label.pack(in_=self.frame)
button1.pack(in_=self.frame)
def do_something(self):
self.label.config(text = "Wait till I'm done...")
self.label.update_idletasks()
time.sleep(2)
print ("end sleep")
self.label.config(text = "I'm done doing...")
def main():
app = SampleApp()
app.mainloop()
return 0
if __name__ == '__main__':
main()
do_something
中的time.sleep
模拟你想做的任何事情。单击按钮开始该过程。
只要给定的函数是 运行。
,这将使带有不确定进度条的弹出窗口与给定的消息一起出现from tkinter import *
import tkinter.ttk as ttk
import threading
# the given message with a bouncing progress bar will appear for as long as func is running, returns same as if func was run normally
# a pb_length of None will result in the progress bar filling the window whose width is set by the length of msg
# Ex: run_func_with_loading_popup(lambda: task('joe'), photo_img)
def run_func_with_loading_popup(func, msg, window_title = None, bounce_speed = 8, pb_length = None):
func_return_l = []
class Main_Frame(object):
def __init__(self, top, window_title, bounce_speed, pb_length):
print('top of Main_Frame')
self.func = func
# save root reference
self.top = top
# set title bar
self.top.title(window_title)
self.bounce_speed = bounce_speed
self.pb_length = pb_length
self.msg_lbl = Label(top, text=msg)
self.msg_lbl.pack(padx = 10, pady = 5)
# the progress bar will be referenced in the "bar handling" and "work" threads
self.load_bar = ttk.Progressbar(top)
self.load_bar.pack(padx = 10, pady = (0,10))
self.bar_init()
def bar_init(self):
# first layer of isolation, note var being passed along to the self.start_bar function
# target is the function being started on a new thread, so the "bar handler" thread
self.start_bar_thread = threading.Thread(target=self.start_bar, args=())
# start the bar handling thread
self.start_bar_thread.start()
def start_bar(self):
# the load_bar needs to be configured for indeterminate amount of bouncing
self.load_bar.config(mode='indeterminate', maximum=100, value=0, length = self.pb_length)
# 8 here is for speed of bounce
self.load_bar.start(self.bounce_speed)
# self.load_bar.start(8)
self.work_thread = threading.Thread(target=self.work_task, args=())
self.work_thread.start()
# close the work thread
self.work_thread.join()
self.top.destroy()
# # stop the indeterminate bouncing
# self.load_bar.stop()
# # reconfigure the bar so it appears reset
# self.load_bar.config(value=0, maximum=0)
def work_task(self):
func_return_l.append(func())
# create root window
root = Tk()
# call Main_Frame class with reference to root as top
Main_Frame(root, window_title, bounce_speed, pb_length)
root.mainloop()
return func_return_l[0]
if __name__ == '__main__':
import time
def task(i):
# The window will stay open until this function call ends.
for x in range(10):
print('hi: ' + i)
time.sleep(.5) # Replace this with the code you want to run
return "this is the func return"
msg = 'running func...'
bounc_speed = 9
pb_length = 200
window_title = "Wait"
r = run_func_with_loading_popup(lambda: task('joe'), msg, window_title, bounc_speed, pb_length)
print('return of test: ', r)