Reputation: 15
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
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
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