如何在函数后停止 tkinter?

Posted

技术标签:

【中文标题】如何在函数后停止 tkinter?【英文标题】:How do I stop tkinter after function? 【发布时间】:2012-04-04 07:47:50 【问题描述】:

我在停止“提要”时遇到问题; cancel 参数似乎对 after 方法没有任何影响。虽然“进纸停止”打印到控制台。

我正在尝试使用一个按钮来启动提要和另一个按钮来停止提要。

from Tkinter import Tk, Button
import random

    def goodbye_world():
        print "Stopping Feed"
        button.configure(text = "Start Feed", command=hello_world)
        print_sleep(True)

    def hello_world():
        print "Starting Feed"
        button.configure(text = "Stop Feed", command=goodbye_world)
        print_sleep()

    def print_sleep(cancel=False):
        if cancel==False:
            foo = random.randint(4000,7500)
            print "Sleeping", foo
            root.after(foo,print_sleep)
        else:
            print "Feed Stopped"


    root = Tk()
    button = Button(root, text="Start Feed", command=hello_world)

    button.pack()


    root.mainloop()

随着输出:

Starting Feed
Sleeping 4195
Sleeping 4634
Sleeping 6591
Sleeping 7074
Stopping Feed
Sleeping 4908
Feed Stopped
Sleeping 6892
Sleeping 5605

【问题讨论】:

我不完全确定 tkinter 是如何工作的,但这对我来说看起来很像一个线程问题。如果你取消一个(线程安全的)全局,这能解决问题吗? @mklauber:不,不是线程问题。 Tkinter 是单线程的。 @BryanOakley:谢谢。这就是我发表评论的原因。我不确定,所以我只是想提出这个问题。 【参考方案1】:

问题在于,即使您使用True 调用print_sleep 来停止循环,也已经有一个待处理的作业等待触发。按下停止按钮不会触发新作业,但旧作业仍然存在,并且当它调用自身时,它会传入 False 导致循环继续。

您需要取消挂起的作业以使其无法运行。例如:

def cancel():
    if self._job is not None:
        root.after_cancel(self._job)
        self._job = None

def goodbye_world():
    print "Stopping Feed"
    cancel()
    button.configure(text = "Start Feed", command=hello_world)

def hello_world():
    print "Starting Feed"
    button.configure(text = "Stop Feed", command=goodbye_world)
    print_sleep()

def print_sleep():
    foo = random.randint(4000,7500)
    print "Sleeping", foo
    self._job = root.after(foo,print_sleep)

注意:确保在某处初始化self._job,例如在应用程序对象的构造函数中。

【讨论】:

我需要这样做,但我需要更多细节 - 请您提供一个完整的示例,包括如何“在某处初始化 self._job,例如在您的应用程序对象的构造函数中。”? 如何获取root.after()的id?致电root.after_cancel()【参考方案2】:

当您调用root.after(...) 时,它会返回一个标识符。您应该跟踪该标识符(例如,将其存储在实例变量中),然后您可以稍后调用 root.after_cancel(after_id) 来取消它。

【讨论】:

如何获取id?【参考方案3】:

这是我的答案,只添加了 3 行代码。答案在于使用.after_cancel(x),简单来说就是“停止做'x'工作”。我相信代码的可读性,所以我只对完成这项工作的代码进行了最小的更改。请看一看。谢谢。

from tkinter import Tk, Button
import random

keep_feeding = None


def goodbye_world():
    print("Stopping Feed")
    button.configure(text="Start Feed", command=hello_world)
    print_sleep(True)


def hello_world():
    print("Starting Feed")
    button.configure(text="Stop Feed", command=goodbye_world)
    print_sleep()


def print_sleep(cancel=False):
    global keep_feeding
    if not cancel:
        foo = random.randint(1000, 2500)
        print(f"Sleeping foo")
        keep_feeding = root.after(foo, print_sleep)
    else:
        root.after_cancel(keep_feeding)
        print("Feed Stopped")


root = Tk()
button = Button(root, text="Start Feed", command=hello_world)

button.pack()

root.mainloop()

【讨论】:

以上是关于如何在函数后停止 tkinter?的主要内容,如果未能解决你的问题,请参考以下文章

单击按钮后如何将输入值(TKinter)传递给其他类中的函数并使用传递的值运行函数[重复]

如何从Tkinter,Python中的Text小部件中移除焦点

tkinter“window.after”循环在夜间 Windows 睡眠/恢复后停止

如何在 tkinter 中显示函数的值?

Python中tkinter包如何提取文本框文字到函数之外?

如何在异常发生后立即停止执行函数? [Python]