'how to change label text in Tkinter with callback function out of window.mainloop
im triggering callback function witch reads encoder output
with GPIO.add_event_detect
so the global counter
has current value, but i cant pass it to tkinter like i did with listbox.insert(END,counter)
import RPi.GPIO as GPIO
from tkinter import ttk
import tkinter as tk
counter = 0
# GPIO Pins #
A = 17
B = 27
#-----------#
# GPIO settings
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
#
GPIO.setup(A, GPIO.IN)
GPIO.setup(B, GPIO.IN)
def Enc(A):
global counter
sleep(0.002)
input_A = GPIO.input(A)
input_B = GPIO.input(B)
if (input_A == 1) and (input_B == 0):
counter += 1
print (counter)
#listbox.insert(END,counter)
elif (input_A == 1) and (input_B == 1):
counter -= 1
print (counter)
#listbox.insert(END,counter)
else:
return
# GPIO output detection
GPIO.add_event_detect(A, GPIO.RISING, callback=Enc, bouncetime=10)
# window settings
window = tk.Tk()
window.title("encoder_value")
# string value?
window.Enc_counter_str = tk.StringVar(value=counter)
# label
tk.Label(window, text='Enc:',fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic").grid(column=0, row=0, **padding)
# output label
window.Enc_label = tk.Label(window)
window.Enc_label.grid(column=0, row=2, columnspan=1, **padding)
window.Enc_label.config(text=window.Enc_counter_str.get(),fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")
# tk window loop
window.mainloop()
Solution 1:[1]
So from what I can understand after reading your question, it seems like you are trying to update the value of window.Enc_label everytime the value of counter changes.
The problem here is with this line -:
window.Enc_counter_str = tk.StringVar(value=counter)
Here when you set value of the string var to counter, you do are only assigning the "that time" value of counter(lets say counter was 1 when this line was executed so value of string var is assigned 1 not the reference to the actual variable.)
But it works, since you do expect the initial value to be the same too. The other problem is that you are not updating the value of the string var, since you assumed the string var had the counter's reference stored but it does not.
So everytime you modify the value of counter you can do this -:
def Enc(A):
global counter
sleep(0.002)
input_A = GPIO.input(A)
input_B = GPIO.input(B)
if (input_A == 1) and (input_B == 0):
counter += 1
print (counter)
elif (input_A == 1) and (input_B == 1):
counter -= 1
print (counter)
else:
return
window.Enc_counter_str.set(counter)
Also now you want the Label object to be right away aware that the string variable is where it will pick it's value from, so it checks it regularly for an update, you can do so by passing the textvariable argument like so -:
window.Enc_label = tk.Label(window, textvariable = window.Enc_counter_str)
There is also another way which is not this neat, but a possible working solution too which is you run this line everytime you update the counter -:
window.Enc_label.config(text=window.Enc_counter_str.get(),fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")
Now this line currently you are only running at initialization of the Label object and thus the text is not updated.
But with our first method this line can be shortened to -:
window.Enc_label.config(fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic")
Now also make sure you place your label declaration before the function, so that python already knows about the string var you are referencing.
The Final code becomes -:
import RPi.GPIO as GPIO
from tkinter import ttk
import tkinter as tk
counter = 0
# GPIO Pins #
A = 17
B = 27
#-----------#
# GPIO settings
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
#
GPIO.setup(A, GPIO.IN)
GPIO.setup(B, GPIO.IN)
# window settings
window = tk.Tk()
window.title("encoder_value")
# string value?
window.Enc_counter_str = tk.StringVar(value=counter)
# label
tk.Label(window, text='Enc:',fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic").grid(column=0, row=0, **padding)
# output label
window.Enc_label = tk.Label(window, textvariable = window.Enc_counter_str) # CHANGE 1
window.Enc_label.grid(column=0, row=2, columnspan=1, **padding)
window.Enc_label.config(fg = "medium violet red", bg = "light grey", font = "Helvetica 16 bold italic") # CHANGE 2
def Enc(A):
global counter
sleep(0.002)
input_A = GPIO.input(A)
input_B = GPIO.input(B)
if (input_A == 1) and (input_B == 0):
counter += 1
print (counter)
elif (input_A == 1) and (input_B == 1):
counter -= 1
print (counter)
else:
return
window.Enc_counter_str.set(counter) # CHANGE 3
# GPIO output detection
GPIO.add_event_detect(A, GPIO.RISING, callback=Enc, bouncetime=10)
# tk window loop
window.mainloop()
Solution 2:[2]
Just use window.Enc_label["text"] = str(counter)
in your Enc
function.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | ElMent |