Reputation: 13
import sys
from tkinter import *
def run_GUI():
# create the window
root = Tk()
frame = Frame(root)
frame.pack()
#modify root window
root.title("Simple GUI")
root.geometry("700x300") # w x h
def SP2T(): # Edit occurs here where I forgot to pit that the button was created in a called funtction
#Creates Row
frameSP2T = Frame(root)
frameSP2T.pack(side = TOP)
#Creating Buttons First Row
button1 = Button(frameSP2T, padx=13, pady = 6, bd=4, text="SW02",fg = "black", command = SW02)
button1.pack(side = LEFT)
def SW02():
print("SW02 is on")
button1["fg"] = "green"
#Sets up initial boot screen
#Creates Row
topframe = Frame(root)
topframe.pack(side = TOP)
#Creating Buttons First Row
buttonA = Button(topframe, padx=13, pady = 6, bd=4, text="SP2T",fg = "black", command = SP2T)
buttonA.pack(side = LEFT)
buttonB = Button(topframe, padx=12, pady = 6, bd=4, text="SP4T",fg = "black")
buttonB.pack(side = LEFT)
buttonC = Button(topframe, padx=12, pady = 6, bd=4, text="SP12T",fg = "black")
buttonC.pack(side = LEFT)
buttonD = Button(topframe, padx=12, pady = 6, bd=4, text="QUIT", fg="red",command=frame.quit)
buttonD.pack(side = LEFT)
#Kick off event loop
root.mainloop()
return
run_GUI()
And I got the error:
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
return self.func(*args)
File "C:\Python34\gui_attempt.py", line 25, in SW02
button1["fg"] = "green"
NameError: name 'button1' is not defined
Updated version which hopefully shows the whole picture
There's more to this program so that's why it says line 60, but this is the problem area. I'm trying to change the button's color when pressed.
Upvotes: 0
Views: 2990
Reputation: 9633
You're dealing with scope issues. The exception is occurring in the function SW02()
because you're trying to modify an object that is not in the function's scope. You need to pass it in. Change SW02()
to the following:
def SW02(button1):
print("SW02 is on")
button1["fg"] = "green"
Since you're using the function as an action for a command, you have a few options to actually pass it in.
Use a lambda:
button1 = Button(frameSP2T, padx=13, pady = 6, bd=4, text="SW02",fg = "black", command = lambda: SW02(button1))
Use functools.partial:
from functools import partial
# other stuff
_SW02 = partial(SW02, button1)
button = Button(frameSP2T, padx=13, pady = 6, bd=4, text="SW02",fg="black", command=_SW02)
Alternatively, as suggested in jonrsharpe's answer, you could refactor your whole GUI function into a class, and have all of your widgets be class members, then associate your widget actions with class methods instead of plain functions. That way, all of your functions that modify GUI components would have access to them.
Upvotes: 0
Reputation: 122024
The simplest fix is to add global button
to the start of the two functions that need access to that object:
def SP2T():
global button1
...
def SW02():
global button1
...
However, the use of global
is generally a bad sign - instead, you could take a class-based approach, as in this simple example:
import tkinter as tk
class MyGui(tk.Tk):
def __init__(self):
super(MyGui, self).__init__()
self.create_widgets()
def create_widgets(self):
self.frame = tk.Frame(self)
self.frame.pack()
self.buttonA = tk.Button(self.frame, padx=13, pady=6, bd=4, text="SP2T",
fg="black", command=self.SP2T)
self.buttonA.pack(side=tk.LEFT)
def SW02(self):
print("SW02 is on")
self.button1["fg"] = "green"
def SP2T(self):
self.button1 = tk.Button(self.frame, padx=13, pady=6, bd=4, text="SW02",
fg="black", command=self.SW02)
self.button1.pack(side=tk.LEFT)
if __name__ == "__main__":
root = MyGui()
root.mainloop()
Upvotes: 2