【问题标题】:triggering and stopping a process with tkinter buttons使用 tkinter 按钮触发和停止进程
【发布时间】:2020-11-30 18:49:34
【问题描述】:

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

我希望变量“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:

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

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()

【问题讨论】:

  • 我很困惑,按下按钮时变量没有变化?
  • 添加第三个按钮,只打印出值。你会看到它正在被改变。此外,将全局变量与类一起使用通常被认为是不好的做法。
  • 我已经编辑了上一个问题,让问题更容易理解,原来的表述确实不清楚。

标签: python user-interface tkinter callback python-multithreading


【解决方案1】:

如果你想打印出 onetwo 的 if 语句只运行一次 每次按下按钮时,我建议将 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()

【讨论】:

  • 如果'global a'是它的唯一功能,你也可以删除它
  • 我已对我的原始问题进行了编辑,以使问题更易于理解,但感谢第一个答案,它实际上为解决问题的可能方法开辟了一个视角。
【解决方案2】:

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

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

会将a 的值(因为a 是原始类型int)传递给tester,即0

您可以使用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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多