【问题标题】:windows thinks tkinter is not respondingwindows 认为 tkinter 没有响应
【发布时间】:2015-04-27 14:27:55
【问题描述】:

我在 python 中有一个小应用程序,除了这个小问题外,它运行良好:它应该连续运行一个循环,直到用户通过按钮告诉它停止,但是当我点击开始按钮时,Windows 告诉我它不是回应。现在,如果我编写一个简单的打印语句,一切正常:

   def update(self):
      self.bStart.config(state = 'disabled')
      self.bStop.config(state = 'active')

      self.running = True
      self.toRun = True
      while self.toRun:
          [...do some stuff...]
          time.sleep(self.toWait)
          print("i'm alive")

但是,如果没有 print 语句,它只会冻结并进入“不响应”状态,我正在徘徊是否有办法防止这种情况发生。

【问题讨论】:

  • 如果你在 tkinter,为什么你使用 time.sleep() 而不是坐在你的 app.mainloop() 中?
  • 您几乎不应该致电time.sleep,因为它确实会阻止您的应用响应。
  • @BryanOakley 在这种情况下我可以使用什么作为替代方案,这会使 tkinter 等待一段时间?
  • @KGS:在基于事件的程序中,它总是在等待。您不需要添加人工等待。如果你想在一段时间后做某事,你可以调用一个widget的after方法来触发以后的功能。
  • @BryanOakley 就我而言,我在画布上有一些用户输入;当按下start 按钮时,画布开始不断更新自身,使用每次更新的结束状态作为下一次更新的起点,循环直到按下stop 按钮。然而,如果没有等待时间,这一切都发生得太快了,用户应该在发生变化时观察它们,所以time.wait() 似乎是一个非常好的主意,因为我可以包含一个滑块来配置一切的速度去。我读了一些关于after 方法的内容,它似乎没有相同的目的

标签: python tkinter


【解决方案1】:

作为一般规则,您不应该在 GUI 中调用 sleep,也不应该有更新显示的循环。如果您要定期更新显示,正确使用after 会使循环变得不必要。

一般的想法是编写一个执行单个更新的函数(即:否则您将拥有作为循环体的内容)。然后,让该函数通过after 调用自身。

这是一个示例,您可以看到条形图随着时间的推移而增长,而无需使用循环:

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.canvas = tk.Canvas(self)
        self.start_button = tk.Button(self, text="start", command=self.on_start)
        self.stop_button = tk.Button(self, text="stop", command=self.on_stop)

        self.start_button.pack()
        self.stop_button.pack()
        self.canvas.pack(fill="both", expand=True)

        # call on_stop to initialize the state of the buttons
        self.on_stop()

    def on_start(self):
        """Start the animation"""
        self.canvas.delete("all")
        self.rect_id = self.canvas.create_rectangle(0,0,1,20, fill="blue")

        self.running = True
        self.start_button.configure(state="disabled")
        self.stop_button.configure(state="normal")
        self.draw_one_frame()

    def on_stop(self):
        """Stop the animation"""
        self.start_button.configure(state="normal")
        self.stop_button.configure(state="disabled")
        self.running = False

    def draw_one_frame(self):
        """Draw a single frame of animation"""
        (x0, y0, x1, y1) = self.canvas.coords(self.rect_id)
        if x1 < self.canvas.winfo_width():
            x1 += 1
        else:
            x1 = 1

        self.canvas.coords(self.rect_id, (x0, y0, x1, y1))

        if self.running:
            self.after(10, self.draw_one_frame)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

【讨论】:

  • 谢谢我现在明白了,我还没有意识到after 是如何工作的,我明天试试(;
猜你喜欢
  • 2016-01-10
  • 2019-06-02
  • 2019-01-10
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
相关资源
最近更新 更多