( прокрутите вниз, чтобы увидеть отредактированную версию этого вопроса )

Я ожидаю, что переменная «a», сделанная глобальной в функции обратного вызова «play», будет обновляться каждый раз, когда я нажимаю кнопки «play» или «stop». Как вы можете видеть, запустив код, функция обратного вызова обновляет свое значение всякий раз, когда я нажимаю кнопки, но если попытаться проверить значение глобальной переменной в основном цикле tkinter, я получаю обновление только тогда, когда программа сначала запускается, а затем ничего не меняется.

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()
-1
CMA 30 Ноя 2020 в 21:49

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()
1
acw1668 1 Дек 2020 в 02:07

Что оператор 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()
2
Flapjack 30 Ноя 2020 в 19:01