当前位置: 首页 > 知识库问答 >
问题:

Tkinter-如何使用停止按钮停止循环?

傅英喆
2023-03-14

我有一个程序,它每秒钟响一次,直到停止。问题是,在我按下“开始”并发出嘟嘟声后,我无法单击“停止”按钮,因为窗口冻结。欢迎任何帮助。

#!/usr/bin/python
import Tkinter, tkMessageBox, time, winsound, msvcrt

running = True

Freq = 2500
Dur = 150

top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200

def start():
    sec = 0
    while running:
        if sec % 1 == 0:
            winsound.Beep(Freq, Dur)

        time.sleep(1)
        sec += 1

def stop():
    running = False

startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)

startButton.pack()
stopButton.pack()

top.mainloop()

共有3个答案

汪高岑
2023-03-14

问题是start()中的while循环阻塞了GUI处理程序mainloop()。尝试使用Tk。在<代码>开始()中的()之后

def start(force=True):
    global running
    if force:
        running = True
    if running:
        winsound.Beep(Freq, Dur)
        top.after(1000, start, False)

并更改Stop()

def stop():
    global running
    running = False
呼延靖
2023-03-14

您的代码有顶部。mainloop()。所以这就像是循环中的循环。

您可以创建一个函数,该函数对循环主体执行您想要的操作。它应该对循环进行一次迭代。一旦完成,它需要安排在将来的某个时候使用之后的再次调用它自己。未来多远定义了循环运行的速度。

然后,您可以在取消后使用来取消事件。下面的代码对我有用

import Tkinter, tkMessageBox, time, winsound, msvcrt

Freq = 2500
Dur = 150

top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200

def start():
    global job1
    if running == True:
        winsound.Beep(Freq, Dur)
        job1 = top.after(1000, start)  # reschedule event in 1 seconds

def stop():
    global job1
    top.after_cancel(job1)

startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)

startButton.pack()
stopButton.pack()
#top.after(1000, start)
top.mainloop()

胡鸿远
2023-03-14

您的代码有几个错误。首先,您不应该在Tkinter程序中使用time.sleep(),因为它会干扰main循环()。相反,人们通常使用通用的小部件方法。在()之后来安排函数在指定的延迟后运行。

其次,您没有正确使用全局变量。当您为函数中的命名变量赋值时,它将创建一个局部变量,除非该名称之前已声明为global。例如,您的stop()函数正在创建一个名为的局部变量,运行并将其值设置为0,而不是更改同名全局变量的值。

前面的规则不适用于仅引用(读取)变量的当前值。这就是为什么在start()中没有声明FreqDur全局变量是可以的。

另一个问题是start()函数中的sec%1==0。任何值%1都是0。要检查奇数/均匀度,请使用秒%2

这是一个工作版本,它也被重新格式化,以更紧密地遵循PEP8风格的Python代码指南。

try:
    import tkinter as tk
except ModuleNotFoundError:
    import Tkinter as tk  # Python 2.
import time
import winsound

FREQ = 2500
DUR = 150

after_id = None
secs = 0

def beeper():
    global after_id
    global secs

    secs += 1
    if secs % 2 == 0:  # Every other second.
        winsound.Beep(FREQ, DUR)
    after_id = top.after(1000, beeper)  # Check again in 1 second.

def start():
    global secs

    secs = 0
    beeper()  # Start repeated checking.

def stop():
    global after_id

    if after_id:
        top.after_cancel(after_id)
        after_id = None


if __name__ == '__main__':

    top = tk.Tk()
    top.title('MapAwareness')
    top.geometry('200x100')

    startButton = tk.Button(top, height=2, width=20, text="Start", command=start)
    stopButton = tk.Button(top, height=2, width=20, text="Stop", command=stop)
    startButton.pack()
    stopButton.pack()

    top.mainloop()

由于这个答案已经变得相当流行,我想谈谈另一个稍微更高级的话题——即如何让代码更加面向对象,从而通过消除几乎所有全局变量来简化事情。

try:
    import tkinter as tk
except ModuleNotFoundError:
    import Tkinter as tk  # Python 2.
import time
import winsound

FREQ = 2500
DUR = 150

class Application(tk.Frame, object):
    def __init__(self, master=None):
        super(Application, self).__init__(master)  # Call baseclass constructor.
        self.after_id = None
        self.secs = 0

        # Create widgets,
        startButton = tk.Button(top, height=2, width=20, text="Start", command=self.start)
        stopButton = tk.Button(top, height=2, width=20, text="Stop", command=self.stop)
        startButton.pack()
        stopButton.pack()

    def beeper(self):
        self.secs += 1
        if self.secs % 2 == 0:  # Every other second.
            winsound.Beep(FREQ, DUR)
        self.after_id = top.after(1000, self.beeper)  # Check again in 1 second.

    def start(self):
        self.secs = 0
        self.beeper()  # Start repeated checking.

    def stop(self):
        if self.after_id:
            top.after_cancel(self.after_id)
            self.after_id = None


if __name__ == '__main__':

    top = tk.Tk()
    app = Application()
    app.master.title('MapAwareness')
    app.master.geometry('200x100')
    app.mainloop()

 类似资料:
  • 启动无限循环后,我无法关闭JFrame。 我想停止无限循环使用停止按钮。 我用开始按钮开始一个无限循环。我想用“停止”按钮关闭那个回路。 > if(stop.getModel(). isP的()){中断;}不工作 actionListener用于识别按钮单击并在循环也不起作用时使用中断语句终止 点击停止按钮,无限循环必须终止。在使用start Button启动无限循环后,我无法使用JFrame中的

  • 问题内容: 因此,我有一个Tkinter GUI,其中有两个简单的选项,即开始和停止按钮。我已经定义了GUI布局: 此处的“开始”按钮运行无限循环扫描,而“停止”按钮在按下时应会中断: 但是,当我按下“开始”按钮时,它总是被按下(假定由于无限循环)。但是,我 无法单击“停止”按钮 来打破while循环。 问题答案: 您不能在Tkinter事件循环所处的同一线程中启动循环。这样做将阻塞Tkinter

  • 问题内容: 我正在编写代码以确定nxn列表中的每个元素是否相同。即返回true,但将返回false。我正在考虑编写一个代码,当它发现与第一个元素不同的元素时立即停止。即: 我想停止此循环, 然后返回false。否则返回true。我将如何实施呢? 问题答案: 使用和为此。可以使用以下命令在Python中完成打破嵌套循环的操作: 另一种方法是将所有内容包装在函数中,并用于从循环中退出。

  • 问题内容: 我试图用图像精灵建立一个加载指示器,然后我想到了这个功能 所以输出看起来像这样 我不得不使用setBgPosition(); 在其他内部保持循环运行,所以现在我的问题是一旦我想要[加载完成],如何停止该循环? 问题答案: 返回计时器句柄,您可以使用该句柄停止超时。 因此,例如: 因此,您可以将其用作: 请注意,我没有将其再次调用,而是将其重新设置为。否则,这将行不通。另请注意,我已将超

  • 我正在使用python创建一个控制Tkinter窗口的类对象。我的代码如下所示: 我希望能够启动一个类的实例,然后像这样停止它: 一切正常,窗口在上成功创建,单击按钮并执行时窗口消失。问题是主循环继续运行。我必须使用Ctrl C手动杀死程序,它显示它在。 如果我只是在一个普通的文件中而不是在一个类中执行所有tkinter代码,那么一切都是一样的,但是当我在root上调用destroy时,mainl

  • 问题内容: 我想如果用户按下主页按钮,我的服务将停止,这是我的代码,但对我不起作用,请帮助我: 谢谢 问题答案: 如果您试图确保该服务仅在相关活动可见时运行,则更好的解决方案是在用户正在运行的任何活动的onPause()方法中停止该服务。这样,当用户按下“返回”时和当用户按下“主页”时,将处理事件。 同样,您可以将服务绑定到一个或多个活动。当绑定到绑定服务的所有活动停止时,绑定服务将被销毁。