【问题标题】:how to show a loading message in tkinter如何在 tkinter 中显示加载消息
【发布时间】:2015-07-11 14:23:31
【问题描述】:

我是 tkinter 的新手。我制作了所需的对话框。我的一项功能需要一些时间来处理。所以我想在该函数开始执行之前显示“正在加载...”消息。

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

当点击此按钮时 compare() 函数开始执行。我想在该功能启动之前显示加载消息。我尝试使用 label ,以便在 compare() 函数开始时为其设置一个值。但只有在函数执行完成后才会生效。

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

【问题讨论】:

    标签: python tkinter loading feedback


    【解决方案1】:

    看看manual for widgetsw.wait_visibility(window) 等到小部件可见。事情的“正常”方式(在所有 GUI 工具包中)是将所有绘图命令(例如您的标签)放在等待列表中,并在有时间时进行实际绘图,优先考虑其他事件)。从页面:

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

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

    当然,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 模拟您想做的任何事情。点击按钮开始进程。

    【讨论】:

      【解决方案2】:

      只要给定的函数正在运行,就会出现一个带有不确定进度条的弹出窗口和给定的消息。

      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)    
      

      【讨论】:

      • 我很想知道如何从另一个父窗口实现这一点,而不是让不确定的进度窗口成为根。
      • 它对我有用,但主应用程序仍然打开。我必须添加 os._exit(1) 才能完成应用程序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2021-06-12
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 2016-11-06
      • 2022-08-09
      相关资源
      最近更新 更多