I have a class with a button, it runs the command automatically when the gui is constructed (which I don't want it to do) but then doesn't work again after. What am I doing wrong? Built-in commands such as endcommand work as they should.
relevant excerpts (ignore the indent problem at the very beginning)
class GuiPart(object):
def __init__(self, master, queue, endCommand):
self.queue = queue
# Set up the GUI
#tkinter.Button(master, text='Done', command=endCommand).grid(row=6,column=6)
tkinter.Button(text='Update Variables', command=self.updateValues()).grid(row=3)
Lp_pacingState = tkinter.Label(text="p_pacingState")
Lp_pacingState.grid(row=1, column=3)
Tp_pacingState = tkinter.Label(bg="white", relief="ridge",justify="center",width=9)
Tp_pacingState.grid(row=1, column=4)
....
self.textBoxes = {"p_pacingState" : Tp_pacingState, "p_pacingMode" : Tp_pacingMode,
"p_hysteresis" : Tp_hysteresis, "p_hysteresisInterval" : Tp_hysteresisInterval,
"p_lowrateInterval" : Tp_lowrateInterval, "p_vPaceAmp" : Tp_vPaceAmp,
"p_vPaceWidth" : Tp_vPaceWidth, "p_VRP" : Tp_VRP}
#def updateValues(self,input):
def updateValues(self):
testInput = ["p_pacingState=3", "garbage=poop", "p_VRP=5"]
for updates in testInput:
print("zzzz")
var = updates.split("=")
try:
self.textBoxes[var[0]].config(text = var[1])
except:
pass
So I get "zzzz" printed 3 times at construction of gui (labels don't update their text though) and the button doesn't work after that. Also if there's a better way to update boxes please tell me. I get input from a stream in no particular order or relevance.
Answer
The issue you're experiencing arises because the command
argument in the Button
widget is being set to the result of self.updateValues()
(i.e., the function is being called immediately during the GUI construction), instead of being set to a reference to the method itself, which is what you want. When you add the parentheses self.updateValues()
, it calls the method immediately and assigns its result (which is None
) to the command
, causing the button to fail to work after that.
Fixing the Issue:
To fix this, you should remove the parentheses from self.updateValues()
in the Button
constructor. This will pass the method reference to the button, so it will only be called when the button is clicked.
Here's the corrected part of your code:
class GuiPart(object):
def __init__(self, master, queue, endCommand):
self.queue = queue
# Set up the GUI
tkinter.Button(text='Update Variables', command=self.updateValues).grid(row=3)
Lp_pacingState = tkinter.Label(text="p_pacingState")
Lp_pacingState.grid(row=1, column=3)
Tp_pacingState = tkinter.Label(bg="white", relief="ridge", justify="center", width=9)
Tp_pacingState.grid(row=1, column=4)
# ...
self.textBoxes = {"p_pacingState": Tp_pacingState, "p_pacingMode": Tp_pacingMode,
"p_hysteresis": Tp_hysteresis, "p_hysteresisInterval": Tp_hysteresisInterval,
"p_lowrateInterval": Tp_lowrateInterval, "p_vPaceAmp": Tp_vPaceAmp,
"p_vPaceWidth": Tp_vPaceWidth, "p_VRP": Tp_VRP}
def updateValues(self):
testInput = ["p_pacingState=3", "garbage=poop", "p_VRP=5"]
for updates in testInput:
print("zzzz")
var = updates.split("=")
try:
self.textBoxes[var[0]].config(text=var[1])
except:
pass
Explanation:
- The problem was that
command=self.updateValues()
in the button creation was immediately callingself.updateValues()
and passing the result (which isNone
) as the command for the button. What you want instead is passing the function referenceself.updateValues
(without the parentheses), so that it only gets executed when the button is clicked.
Additional Notes:
-
Make sure that the
updateValues
method updates the labels correctly by ensuring that the keys inself.textBoxes
(like"p_pacingState"
,"p_VRP"
, etc.) match the keys you're using intestInput
. -
You might want to handle the exceptions more carefully instead of using a general
except: pass
. For example, you can log or print a message when an invalid key is encountered so that you can debug it easily.
def updateValues(self):
testInput = ["p_pacingState=3", "garbage=poop", "p_VRP=5"]
for updates in testInput:
print("zzzz")
var = updates.split("=")
try:
if var[0] in self.textBoxes: # Ensure the key exists
self.textBoxes[var[0]].config(text=var[1])
else:
print(f"Invalid key: {var[0]}") # Log invalid keys
except Exception as e:
print(f"Error updating {var[0]}: {e}")
This should now behave as expected: The updateValues
method will not run at GUI construction time but will be triggered when the button is clicked.