简体   繁体   English

如何通过在 Tkinter (Python) 中制作正确的“停止”按钮来中断线程/进程?

[英]How to interrupt a thread/process by making a correct "Stop" button in Tkinter (Python)?

I want some basics on the problem of making some sort of "Stop" button that in my case terminates the series of beeps:我想要一些关于制作某种“停止”按钮的问题的基础知识,在我的情况下,该按钮会终止一系列哔哔声:

from tkinter import *
import winsound
from random import randint

class App(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.widgets()

    def widgets(self):
        self.beep = Button(self, text = "Beep", command = play_beep)
        self.beep.pack()
        self.stop = Button(self, text = "Stop", command = stop_beep)
        self.stop.pack()

go_on = True
def play_beep():
    count = 10
    while go_on == True and count != 0:
        winsound.Beep(randint(100, 2500), 200)
        count -= 1

def stop_beep():
    go_on = False

root = Tk()
app = App(root)
root.mainloop()

When I press the "Beep" button it gets stuck as well as all the GUI until the beeps end.当我按下“Beep”按钮时,它和所有 GUI 都会卡住,直到蜂鸣声结束。 Could anyone tell me how to fix it?谁能告诉我如何修复它?

First off, your question has nothing to do about threads or processes.首先,您的问题与线程或进程无关。 Tkinter is single-threaded. Tkinter 是单线程的。

If you want to run some function periodically in a tkinter program, you must give the event loop a chance to process events.如果您想在 tkinter 程序中定期运行某个函数,您必须给事件循环一个处理事件的机会。 The typical solution is to do it like this:典型的解决方案是这样做:

def play_beep(count=10):
    if go_on and count != 0:
        winsound.Beep(randint(100, 2500), 200)
        root.after(1000, play_beep, count=1)

This will cause the beep to play every second (1000ms) for ten iterations.这将导致哔声每秒(1000 毫秒)播放十次。 In between each call, the event loop will have a chance to process other events.在每次调用之间,事件循环将有机会处理其他事件。

Now, if the code you are running takes a long time, you're going to have to run that code in a separate thread or process.现在,如果您运行的代码需要很长时间,您将不得不在单独的线程或进程中运行该代码。 I know nothing about winsound.Beep so I don't know if that's necessary or not.我对winsound.Beep所以我不知道是否有必要。

Second, to be able to interrupt it, you need to make go_on global, otherwise you're simply setting a local variable that never gets used.其次,为了能够中断它,您需要将go_on全局,否则您只是设置了一个永远不会被使用的局部变量。

def stop_beek():
    global go_on
    go_on = False

I don't use TKinter, but I believe your button press is not creating a separate thread or process.我不使用 TKinter,但我相信您的按钮按下不会创建单独的线程或进程。 The reason why your button gets stuck is because your play_beep loop is blocking your GUI execution loop.你的按钮卡住的原因是你的 play_beep 循环阻塞了你的 GUI 执行循环。 So we use threading.所以我们使用线程。 The thread executes at the same time as your GUI, so you can basically do two things at once (listen for GUI events and play beep noises).该线程与您的 GUI 同时执行,因此您基本上可以一次做两件事(监听 GUI 事件并播放哔声)。

import threading

class App(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.is_playing = False
        self.pack()
        self.widgets()

    def widgets(self):
        self.beep = Button(self, text = "Beep", command = self.play_beep)
        self.beep.pack()
        self.stop = Button(self, text = "Stop", command = self.stop_beep)
        self.stop.pack()

    def play_beep(self):
        self.is_running = True
        self.beep_th = threading.Thread(target=self.run)
        self.beep_th.start()

    def run(self):
        count = 10
        while self.is_running == True and count != 0:
            winsound.Beep(randint(100, 2500), 200)
            count -= 1

    def stop_beep(self):
        try:
            self.is_running = False
            self.beep_th.join(0)
            self.beep_th = None
        except (AttributeError, RuntimeError): # beep thread could be None
            pass

    def closeEvent(self, event): # This is a pyside method look for a TKinter equivalent.
        """When you close the App clean up the thread and close the thread properly."""
        self.stop_beep()
        super().closeEvent(event)

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

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