lherron8
lherron8

Reputation: 13

Changing Button Color in a python GUI

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

Answers (2)

skrrgwasme
skrrgwasme

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

jonrsharpe
jonrsharpe

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

Related Questions