如何在tkinter中显示加载消息

时间:2015-07-11 14:23:31

标签: python tkinter loading feedback

我是tkinter的新手。我做了必要的对话框。我的一个功能需要一些时间来处理。所以我想展示一个" loading ..."该函数开始执行之前的消息。

b1 = Button(text = "Compare",command = compare)
b1.pack()

单击此按钮时,compare()函数开始执行。我希望在该函数启动之前显示加载消息。我尝试使用标签,这样我在compare()函数的开头设置了一个值。但它只会在函数完成执行后生效。

我该怎么办?请帮帮我..

2 个答案:

答案 0 :(得分:5)

查看manual for widgetsint {id}等待窗口小部件可见。正常'事物的方式(在所有的GUI工具包中)是将所有绘图命令(例如标签)放在等待列表中,并在有时间时执行实际绘图,优先考虑其他事件)。从页面:

  

等待给定的小部件变得可见。这通常用于等待屏幕上出现新的顶层窗口。喜欢   wait_variable,这个方法进入本地事件循环,所以其他部分   应用程序仍将照常工作。

使用w.wait_visibility(window)的示例来自test_widgets.py代码,其中setup等待小部件真正显示:

wait_visibility

当然,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() 函数确实需要花费一些时间 - 否则标签可能会在屏幕上实际显示之前消失。您的屏幕每秒重绘60次,因此如果比较时间少于16毫秒,您可能看不到任何内容。

编辑:更好的方法是使用compare。这是一些代码:

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() 中的time.sleep模拟您想要做的任何事情。单击按钮开始该过程。

答案 1 :(得分:1)

只要给定功能正在运行,这将使带有不确定进度条的弹出窗口与给定消息一起显示。

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)