简体   繁体   English

如何在 tkinter 中显示加载消息

[英]how to show a loading message in tkinter

I am new to tkinter.我是 tkinter 的新手。 I made the required dialog box.我制作了所需的对话框。 One of my function takes some time to process.我的一个函数需要一些时间来处理。 So i want to show a "loading ... " message before that function starts executing.所以我想在该函数开始执行之前显示“正在加载...”消息。

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

when this button is clicked compare() function start executing.单击此按钮后,compare() 函数开始执行。 i want to show a loading message before that function starts.我想在该功能启动之前显示加载消息。 I tried using a label , such that i set a value to it on the starting of the compare() function.我尝试使用 label ,以便在 compare() 函数开始时为其设置一个值。 but it will only takes effect after the function finish executing.但只有在函数执行完毕后才会生效。

How can i do it?我该怎么做? please help me..请帮我..

Have a look at the manual for widgets .查看小部件手册 w.wait_visibility(window) waits till the widget is visible. w.wait_visibility(window)等待小部件可见。 The 'normal' way of things (in all GUI toolkits) is to put all drawing commands, such as your label, in a waiting list, and do the actual drawing when there's time, prioritizing other events).事情的“正常”方式(在所有 GUI 工具包中)是将所有绘图命令(例如您的标签)放在等待列表中,并在有时间时进行实际绘图,优先考虑其他事件)。 From the page:从页面:

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_variable一样,这个方法进入了一个本地事件循环,所以应用程序的其他部分仍然会照常工作。

An example for the use of wait_visibility comes from the test_widgets.py code, where setup waits for the widget to be really shown:使用wait_visibility一个示例来自test_widgets.py代码,其中 setup 等待小部件真正显示:

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()

Of course, the compare function does have to take some appreciable time - else the label will probably disappear before it can actually be seen on the screen.当然, compare功能确实需要一些可观的时间 - 否则标签可能会在它实际出现在屏幕上之前消失。 Your screen is redrawn 60 times per second, so if the comparing takes less than 16 ms, you'll probably not see anything.您的屏幕每秒重绘 60 次,因此如果比较时间少于 16 毫秒,您可能看不到任何内容。

EDIT: A better way to do this is actually using update_idletasks .编辑:执行此操作的更好方法实际上是使用update_idletasks Here's some code:这是一些代码:

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()

The time.sleep in do_something simulates whatever you want to do.time.sleepdo_something任何你想做的事情会模拟。 Click on the button to start the process.单击按钮开始该过程。

This will make a popup with an indeterminate progress bar appear with a given message for as long as the given function is running.只要给定的函数正在运行,这将使一个带有不确定进度条的弹出窗口与给定的消息一起出现。

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)    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM