SmolBrein
SmolBrein

Reputation: 15

How do I delete a Tkinter label using a button command?

I want my program to run in a way that once the user presses the Info button, a label called GameInfoLabel is displayed due to a command from the Info button. Within the same condition (if the Info button is pressed), I want to add a Back button that deletes/destroys the GameInfoLabel.

I have attempted to implement this in the code below, but I'm getting the message

NameError: name 'GameInfoLabel' is not defined.

from tkinter import * 

root = Tk() 
root.title("Game Menu") 
root.geometry("1920x1080")  
root.resizable(True, True) 

def QuitGameInfo():
    GameInfoLabel.destroy()
    BackInfoButton['state'] = NORMAL


def GameInfo(): 
    RulesNotepad = open("GameInfo.txt",'r')
    Rules = RulesNotepad.read()
    GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140").pack()
    BackInfoButton = Button(root, text = "Back", command = QuitGameInfo).pack() 
    RulesNotepad.close()

button3 = Button(root, text = "Info", command = GameInfo, width = "20", height = "3").pack()

root.mainloop()

Upvotes: 0

Views: 149

Answers (2)

Jack Walton
Jack Walton

Reputation: 181

As mentioned in acw1668's comment GameInfoLabel is local to the GameInfo() method. This means once this method has finished running anything declared in it ceases to exist.

The usual solution to this is passing/returning variables to functions to get results for instance your game info could return the label, however since you want to call these functions automatically when an event occurs, e.g. your button is pressed, this is not so easy.

I believe the easiest solution to your problem would be to declare the GameInfoLabel variable globally (in the global scope), this is not always the best coding practice but I'm not certain of tkinter's ability to pass variables parameters to an event handler and this can be complicated.

Also as mentioned by acw1668 you call .pack() immediately on the new label which is returned from the initialization Label(...). Pack then does not return the label so we do that separately.

This should work, give it a careful read.

from tkinter import * 

root = Tk() 
root.title("Game Menu") 
root.geometry("1920x1080")  
root.resizable(True, True) 

# Declare any global UI Components
GameInfoLabel = None # Dont set a Label yet

def QuitGameInfo():
    GameInfoLabel.destroy()
    BackInfoButton['state'] = NORMAL

def GameInfo(): 
    RulesNotepad = open("GameInfo.txt",'r')
    Rules = RulesNotepad.read()
    GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140")
    GameInfoLabel.pack()

    BackInfoButton = Button(root, text = "Back", command = QuitGameInfo).pack() 
    RulesNotepad.close()

button3 = Button(root, text = "Info", command = GameInfo, width = "20", height = "3")
button3.pack()

root.mainloop()

Upvotes: 0

acw1668
acw1668

Reputation: 47173

The error is due to that GameInfoLabel is a local variable inside GameInfo() and it is not accessible inside QuitGameInfo().

You can fix this error by either declaring GameInfoLabel as global or pass it to QuitGameInfo() via argument. Same apply on BackInfoButton as well.

However you need to fix another issue: both GameInfoLabel and BackInfoButton are None because they are result of pack().

Below is the modified code using global solution:

from tkinter import * 

root = Tk() 
root.title("Game Menu") 
root.geometry("1920x1080")  
root.resizable(True, True) 

def QuitGameInfo():
    GameInfoLabel.destroy()
    #BackInfoButton['state'] = NORMAL   # why ??? Should it be destroyed as well?
    BackInfoButton.destroy()


def GameInfo():
    global GameInfoLabel, BackInfoButton 
    with open("GameInfo.txt",'r') as RulesNotepad:
        Rules = RulesNotepad.read()
    GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140")
    GameInfoLabel.pack()
    BackInfoButton = Button(root, text = "Back", command = QuitGameInfo)
    BackInfoButton.pack() 

Button(root, text = "Info", command = GameInfo, width = "20", height = "3").pack()

root.mainloop()

However I would suggest to use a frame to hold the GameInfoLabel and BackInfoButton and the frame is hidden initially. When Info button is clicked, show the frame. When Back button is clicked, hide the frame.

from tkinter import * 

root = Tk() 
root.title("Game Menu") 
root.geometry("1920x1080")  
root.resizable(True, True) 

def GameInfo():
    with open("GameInfo.txt",'r') as RulesNotepad:
        Rules = RulesNotepad.read()
    GameInfoLabel.config(text=Rules)
    info_frame.pack()  # show the game info frame

Button(root, text="Info", command=GameInfo, width="20", height="3").pack()

# create the game info frame but don't show it initially
info_frame = Frame(root)
GameInfoLabel = Label(info_frame, fg="blue", bg="red", height="14", width="140")
GameInfoLabel.pack()
Button(info_frame, text="Back", command=info_frame.pack_forget).pack()

root.mainloop()

Upvotes: 1

Related Questions