使用 tkinter 按钮触发和停止进程

triggering and stopping a process with tkinter buttons

(向下滚动查看此问题的编辑版本)

我希望在“播放”回调函数中设置为 global 的变量“a”在我每次按下“播放”或“停止”按钮时更新。正如您在 运行 代码中看到的那样,只要我按下按钮,回调函数就会更新它的值,但是如果尝试在 tkinter mainloop 中测试全局变量的值,我只会在程序运行时得到更新首先开始,然后没有任何变化。

from tkinter import *

a = 0

class gui:

    def __init__(self, window):

        # play button
        self.play_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.play_frame.grid(row=0, column=0, padx=1, pady=1)
        self.play_button = Button(self.play_frame, text="play", fg="blue", command=lambda: self.play(1))
        self.play_button.pack()
        # stop button
        self.stop_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.stop_frame.grid(row=0, column=2, padx=1, pady=1)
        self.stop_button = Button(self.stop_frame, text="stop", fg="red", command=lambda: self.play(0))
        self.stop_button.pack()


    def play(self, switch):
        global a
        a = switch
        print (a)

root = Tk()

if a == 1:
    print ("one")
elif a == 0:
    print ("zero")

app = gui(root)
root.mainloop()

编辑 1:

我重新编写了代码,以便使问题更清楚,并模拟在我尝试使用这些简化示例重现的情况下发生的情况。我希望测试器功能根据我按下的每个按钮打印出“运行”或“not 运行”。我是线程中的 运行“测试人员”,因为在实际项目中,我正在处理“测试人员”是一个更复杂的过程:

from tkinter import *
import threading
import time

a = 0

class gui:

    def __init__(self, window):

        # play button
        self.play_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.play_frame.grid(row=0, column=0, padx=1, pady=1)
        self.play_button = Button(self.play_frame, text="play", fg="blue", command=lambda: self.play(1))
        self.play_button.pack()
        # stop button
        self.stop_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.stop_frame.grid(row=0, column=2, padx=1, pady=1)
        self.stop_button = Button(self.stop_frame, text="stop", fg="red", command=lambda: self.play(0))
        self.stop_button.pack()


    def play(self, switch):
        global a
        a = switch
        print (a)

root = Tk()

def tester(trig):
    while True:


        if trig == 1:
            time.sleep(0.5)
            print ("running")
        elif trig == 0:
            time.sleep(0.5)
            print ("not running")
    


t1 = threading.Thread (target = tester, args = [a], daemon = True)
t1.start()

app = gui(root)
root.mainloop()

如果语句只被运行一次,如果你想打印出一个两个 每次按下按钮时,我建议将 if 语句放在 play 函数中。

from tkinter import *

a = 0

class gui:

    def __init__(self, window):

        # play button
        self.play_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.play_frame.grid(row=0, column=0, padx=1, pady=1)
        self.play_button = Button(self.play_frame, text="play", fg="blue", command=lambda: self.play(1))
        self.play_button.pack()
        # stop button
        self.stop_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.stop_frame.grid(row=0, column=2, padx=1, pady=1)
        self.stop_button = Button(self.stop_frame, text="stop", fg="red", command=lambda: self.play(0))
        self.stop_button.pack()


    def play(self, switch):
        global a
        a = switch
        
        if a == 1:
            print ("one")
        elif a == 0:
            print ("zero")

root = Tk()

app = gui(root)
root.mainloop()

将原始类型传递给函数使用 pass by value,因此以下行:

t1 = threading.Thread (target = tester, args = [a], daemon = True)

会将 a 的值(因为 a 是原始类型 int)传递给 tester0.

您可以使用 IntVar 代替 a,这样就可以使用 pass by reference

from tkinter import *
import threading
import time

class gui:
    def __init__(self, window):
        # play button
        self.play_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.play_frame.grid(row=0, column=0, padx=1, pady=1)
        self.play_button = Button(self.play_frame, text="play", fg="blue", command=lambda: self.play(1))
        self.play_button.pack()
        # stop button
        self.stop_frame = Frame(master=window, relief=FLAT, borderwidth=1)
        self.stop_frame.grid(row=0, column=2, padx=1, pady=1)
        self.stop_button = Button(self.stop_frame, text="stop", fg="red", command=lambda: self.play(0))
        self.stop_button.pack()

    def play(self, switch):
        a.set(switch) # update 'a'
        print(a.get())

root = Tk()

a = IntVar(value=0)

def tester(trig):
    while True:
        value = trig.get()
        if value == 1:
            time.sleep(0.5)
            print ("running")
        elif value == 0:
            time.sleep(0.5)
            print ("not running")

t1 = threading.Thread (target = tester, args = [a], daemon = True)
t1.start()

app = gui(root)
root.mainloop()