I've been programming a random operator name generator for Rainbox Six Siege and I want the operators picture to appear when their name comes up. The image appears fine, but it won't go away. This is my Code:
from tkinter import *
import tkinter
import random
names = ['Sledge','Thatcher','Ash','Thermite','Twitch','Montagne','Glaz','Fuze','Blitz','IQ','Buck','Blackbeard','Capitão','Hibana']
name = ["Smoke","Mute","Castle","Pulse","Doc","Rook","Kapkan","Tachanka","Jäger","Bandit","Frost","Valkyrie","Caveira","Echo"]
root = tkinter.Tk()
def pickName():
rad = random.choice(names)
photo = PhotoImage(file=rad+".png")
label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()
nameLabel.configure(text=rad, foreground="white", background="blue")
root.configure(background='blue')
def pickName1(): nameLabel.configure(text=random.choice(name),background="orange",foreground="black")
root.configure(background='orange')
root.title("Operator Picker")
root.geometry("250x100")
nameLabel = tkinter.Label(root, text="", font=('Helvetica', 32))
nameLabel.pack()
Grid()
f1 = tkinter.Frame(root, height=100, width=100) #defines frame size in
pixels
f1.pack(side=tkinter.LEFT) #packs on the left
f1.pack_propagate(0) #tells frame not to let children control size
pickButton1 = tkinter.Button(f1, command=pickName, text="Pick
Attack",background="blue",foreground="white")
pickButton1.pack(fill=tkinter.BOTH, expand=1) #takes up all available space
f2 = tkinter.Frame(root, height=100, width=100)
f2.pack(side=tkinter.RIGHT)
f2.pack_propagate(0)
pickButton2 = tkinter.Button(f2, command=pickName1, text="Pick
Defend",background="orange",foreground="black")
pickButton2.pack(fill=tkinter.BOTH, expand=1)
root.mainloop()
Note: This is still a WIP, all I need is to know how to get rid of the pictures once they appear. This is what it looks like when more than one image appears: https://imgur.com/eroXLLn
You are adding a new Label every time you call that function. Instead, you should make the Label only once (probably in the initialization stage), and update the picture. Just like you update the text for nameLabel, plus the step to keep the reference.
photo_label = tkinter.Label()
def pickName():
rad = random.choice(names)
photo = PhotoImage(file=rad+".png")
photo_label.configure(image = photo)
photo_label.image = photo # keep a reference!
photo_label.pack()
nameLabel.configure(text=rad, foreground="white", background="blue")
and your whole code should look like:
from tkinter import *
import tkinter
import random
names = ['Sledge','Thatcher','Ash','Thermite','Twitch','Montagne','Glaz','Fuze','Blitz','IQ','Buck','Blackbeard','Capitão','Hibana']
name = ["Smoke","Mute","Castle","Pulse","Doc","Rook","Kapkan","Tachanka","Jäger","Bandit","Frost","Valkyrie","Caveira","Echo"]
root = tkinter.Tk()
photo_label = tkinter.Label()
def pickName():
rad = random.choice(names)
photo = PhotoImage(file=rad+".png")
photo_label.configure(image = photo)
photo_label.image = photo # keep a reference!
photo_label.pack()
nameLabel.configure(text=rad, foreground="white", background="blue")
root.configure(background='blue')
def pickName1(): nameLabel.configure(text=random.choice(name),background="orange",foreground="black")
root.configure(background='orange')
root.title("Operator Picker")
root.geometry("250x100")
nameLabel = tkinter.Label(root, text="", font=('Helvetica', 32))
nameLabel.pack()
Grid()
f1 = tkinter.Frame(root, height=100, width=100) #defines frame size inpixels
f1.pack(side=tkinter.LEFT) #packs on the left
f1.pack_propagate(0) #tells frame not to let children control size
pickButton1 = tkinter.Button(f1, command=pickName, text="PickAttack",background="blue",foreground="white")
pickButton1.pack(fill=tkinter.BOTH, expand=1) #takes up all available space
f2 = tkinter.Frame(root, height=100, width=100)
f2.pack(side=tkinter.RIGHT)
f2.pack_propagate(0)
pickButton2 = tkinter.Button(f2, command=pickName1, text="PickDefend",background="orange",foreground="black")
pickButton2.pack(fill=tkinter.BOTH, expand=1)
root.mainloop()
Related
First: In code below i want to use instead of default rectangle button, images prepared by myslef.
This generates some problems (mayby with reference)? This button does not appear as image, also i am not able to use function (name: load_frame_insert()) after click.
Second: I wonder to have 2 bbtns:
Normal: assets/insert_data.png
OnClick: assets/insert_data2.png
Could you help me?
PS. Doesn't work after moving from up-down code to code with functions
import pyodbc
import pandas as pd
import os
import tkinter as tk
from PIL import ImageTk
# DB connector
conn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};'
'SERVER=onyx1905;'
'DATABASE=DW_15;'
'Trusted_Connection=yes')
# variables
name = os.getlogin()
cursor = conn.cursor()
running = True
bg_color_1 = "#205E61"
bg_button = "#1B4E51"
bg_button_ac = "#FFD966"
global img_button_1
def image_button_1(size):
img = tk.PhotoImage(file="assets/insert_data.png")
img = img.subsample(size, size)
return img
#button img: insert_data
#button img: insert_data_on_click
def clear_widgets(frame):
for widget in frame.winfo_children():
widget.destroy()
def load_main_frame():
clear_widgets(frame_insert)
frame_main.tkraise()
frame_main.pack_propagate(False)
# widget frame_main logo
logo_image = ImageTk.PhotoImage(file="assets/xrdl_logo.png")
logo_widget = tk.Label(frame_main, image=logo_image, bg=bg_color_1)
logo_widget.image = logo_image
logo_widget.pack()
# label on 1st frame
tk.Label(
frame_main,
text=(f" Hi {name}, please choose an action "),
bg=bg_button,
fg="white",
font=("TkMenuFont", 12)
).pack(pady=10)
# btn code on 1st frame
tk.Button(
frame_main,
image=image_button_1(1),
bd=0,
relief="groove",
compound=tk.CENTER,
bg=bg_color_1,
fg="yellow",
activeforeground="pink",
activebackground=bg_color_1,
font=("TkMenuFont", 12),
cursor="hand2",
text="",
command=lambda: load_frame_insert()
).pack(pady=5)
def load_frame_insert():
print("Hi XYZ")
# ini for app
main_app = tk.Tk()
main_app.title("SRD Loader")
main_app.eval("tk::PlaceWindow . center")
x = main_app.winfo_screenwidth() // 3
y = int(main_app.winfo_screenheight() * 0.1)
main_app.geometry('500x600+' + str(x) + '+' + str(y))
# frame look
frame_main = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)
frame_insert = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)
for frame in (frame_main, frame_insert):
frame.grid(row=0, column=0)
load_main_frame()
main_app.mainloop()
conn.close()
other related topics but doesnt work
youtube tutorials
For the statement command=image_button_1(1), the image returned by image_button_1(1) will be garbage collected because there is no variable referencing it. That is why you get a button without image.
You need to save the reference of the image, for example using an attribute of the button as below:
image = image_button_1(1)
btn = tk.Button(
frame_main,
image=image,
bd=0,
relief="groove",
compound=tk.CENTER,
bg=bg_color_1,
fg="yellow",
activeforeground="pink",
activebackground=bg_color_1,
font=("TkMenuFont", 12),
cursor="hand2",
text="",
command=lambda: load_frame_insert()
)
btn.pack(pady=5)
btn.image = image # save the reference of the image
I removed three libraries.
I removed image_button_1 function
Added image = tk.PhotoImage(file="p1.png")
Added variable for Button
Change 5 to 25 .pack(pady=25)
Removed lambda and brace bracket command=load_frame_insert
Snippet:
import os
import tkinter as tk
running = True
bg_color_1 = "#205E61"
bg_button = "#1B4E51"
bg_button_ac = "#FFD966"
def clear_widgets(frame):
for widget in frame.winfo_children():
widget.destroy()
def load_main_frame():
clear_widgets(frame_insert)
frame_main.tkraise()
frame_main.pack_propagate(False)
# widget frame_main logo
logo_image = tk.PhotoImage(file="p2.png")
logo_widget = tk.Label(frame_main, image=logo_image, bg=bg_color_1)
logo_widget.image = logo_image
logo_widget.pack()
# label on 1st frame
tk.Label(
frame_main,
text=(f"Hi please choose an action"),
bg=bg_button,
fg="white",
font=("TkMenuFont", 12)
).pack(pady=10)
image = tk.PhotoImage(file="p1.png")
# btn code on 1st frame
btn= tk.Button(
frame_main,
image=image,
bd=0,
relief="groove",
compound=tk.CENTER,
bg=bg_color_1,
fg="yellow",
activeforeground="pink",
activebackground=bg_color_1,
font=("TkMenuFont", 12),
cursor="hand2",
text="",
command=load_frame_insert
)
btn.pack(pady=25)
btn.image = image
def load_frame_insert():
print("Hi XYZ")
# ini for app
main_app = tk.Tk()
main_app.title("SRD Loader")
main_app.eval("tk::PlaceWindow . center")
x = main_app.winfo_screenwidth() // 3
y = int(main_app.winfo_screenheight() * 0.1)
main_app.geometry('500x600+' + str(x) + '+' + str(y))
# frame look
frame_main = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)
frame_insert = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)
for frame in (frame_main, frame_insert):
frame.grid(row=0, column=0)
load_main_frame()
main_app.mainloop()
Screenshot:
I want this entry bar and other contents I'll add to the frame later to be centred correctly, I received this code that supposedly should work but it isn't.
import tkinter as tk
import math
import time
root = tk.Tk()
root.geometry()
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text = "Exit", command = root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root)
main_entry = tk.Entry(root, width = 100, fg = "black")
main_entry.place(x=50, y=50)
frame.place(relx=.5,rely=.5, anchor='center')
root.mainloop()
As you can see the frame isn't centred so how can I fix this?
In order to achieve widget centering on a fullscreen I've had to use grid manager.
The code below works but the exact positioning requires some fiddling with frame padding.
frame padx = w/2-300 and pady = h/2-45 are arbitrary values found using a bit of trial and error.
import tkinter as tk
root = tk.Tk()
root.attributes( '-fullscreen', True )
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
frame = tk.Frame( root )
main_entry = tk.Entry( frame, width = 100 )
main_entry.grid( row = 0, column = 0, sticky = tk.NSEW )
frame.grid( row = 0, column = 0, padx = w/2-300, pady = h/2-45, sticky = tk.NSEW )
exit_button = tk.Button( frame, text = 'Exit', command = root.destroy )
exit_button.grid( row = 1, column = 0, sticky = tk.NSEW )
tk.mainloop()
Frame automatically changes size to size of objects inside Frame (when you use pack()) but you have nothing inside Frame. You put all widgets directly in root - so Frame has no size (width zero, height zero) and it is not visible.
When I use tk.Frame(root, bg='red', width=100, height=100) then I see small red frame in the center.
You have two problems:
(1) you put Entry in wrong parent - it has to be frame instead of root,
(2) you use place() which doesn't resize Frame to its children and it has size zero - so you don't see it. You would have to set size of Frame manully (ie. tk.Frame(..., width=100, height=100)) or you could use pack() and it will resize it automatically.
I add colors for backgrounds to see widgets. blue for window and red for frame.
import tkinter as tk
root = tk.Tk()
root['bg'] = 'blue'
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text="Exit", command=root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root, bg='red')
frame.place(relx=.5, rely=.5, anchor='center')
main_entry = tk.Entry(frame, width=100, fg="black")
main_entry.pack(padx=50, pady=50) # with external margins 50
root.mainloop()
I am writing a program to generate draft emails, and I am trying to set it up with a tkinter GUI. I'm on Python 3.5 with tkinter 8.6.
My issue is that I cannot get rowspan to work. I want to have the first row span a few rows, but when I add 'rowspan' the row doesn't change size. If I add 'sticky=tK.N+tK.S', I get errors that those mean nothing. So then I started messing with how I was importing tkinter, trying it as importing from, importing as tk, importing *, but everything I change breaks soemthing else, and still doesn't get the north-south stickiness that I am looking for so that the row will stretch out and fill the space.
I am pretty sure that this is an issue with how I am importing tkinter, and any advice would be tremendously appreciated. I also can't get tkinter to work if I use 'import tkinter as tk" because then I get errors like name 'StringVar' is not defined". I tried fixing that by moving where my root was declared, but that created issues with GUI.
Help! Thanks :)
import os
# pull in GUI stuff
import tkinter as tk #import Tk, Label, Button, W, E, N, S, StringVar, OptionMenu, Entry, Text, END, WORD
from PIL import Image, ImageTk
path = os.getcwd()
# init GUI
class GUI:
def __init__(self, master):
self.master = master
master.title("Email Draft Builder")
# set logo image
f = os.getcwd() + "\\cgs_logo.gif"
# lock in image for use outside this section
im = Image.open(f)
ph = ImageTk.PhotoImage(im)
# vars to show dynamic text for displays 1 and 2
self.box1_titleText = tk.StringVar()
self.box2_titleText = tk.StringVar()
self.box1_content = tk.StringVar()
self.box2_content = tk.StringVar()
# main/container pane info
self.label = tk.Label(master, text="Email Draft Composer", image = ph, bg = "#ffffff")
self.label.image = ph
self.label.grid(columnspan = 3, row = 0, rowspan = 2, sticky=tk.N+
tk.S, column=1)
# ROW 1
self.readLast_button = tk.Button(master, text="Read Training File", command=self.dataOps)
self.readLast_button.grid(row=3, column=0,sticky=tk.W)
# ROW 2
self.file_button = tk.Button(master, text="Unused", command=self.chooseSite)
self.file_button.grid(row=4, column=0,sticky=tk.W)
# ROW 3
self.pullSite_button = tk.Button(master, text="Show Site Info:", command=self.pullSite)
self.pullSite_button.grid(row=5, column=0,sticky=tk.W)
self.getSite = tk.Entry(master)
self.getSite.grid(row=5, column=1,sticky=tk.W)
# ROW 4
self.sendEmail_button = tk.Button(master, text="Build Email", command=self.sendEmail)
self.sendEmail_button.grid(row=6, column=0,sticky=tk.W)
recipients = ["mgancsos#cogstate.com","mgancsos#gmail.com","kkiernan#cogstate.com;mchabon#cogstate.com","ashortland#cogstate.com"]
self.receiver = tk.StringVar()
self.receiver.set(recipients[0])
self.menu1 = tk.OptionMenu(master, self.receiver, *recipients)
self.menu1.grid(row=6, column=1,sticky=tk.W)
# ROW 5
self.close_button = tk.Button(master, text="Close", command=root.destroy)
self.close_button.grid(row=7, column=0,sticky=tk.W)
# ROW 6
self.box1_title = tk.Label(master, textvariable=self.box1_titleText, bg = "#fffff0", borderwidth=1, relief = "groove", width = 15)
self.box1_title.grid(columnspan=1, row = 8, column=0, sticky=tk.W)
self.box1_pane = tk.Label(master, textvariable=self.box1_content, bg = "#fffff0", borderwidth=1, relief = "groove", width = 55)
self.box1_pane.grid(columnspan=1, row = 8, column=1, sticky=tk.W)
# ROW 7
self.box2_title = tk.Label(master, textvariable=self.box2_titleText, bg = "#ffff00", borderwidth=1, relief = "groove", width = 15)
self.box2_title.grid(columnspan=1, row = 9, column=0, sticky='nw')
self.box2_pane = tk.Label(master, textvariable=self.box2_content, bg = "#ffffff", borderwidth=1, relief = "groove", width = 55)
self.box2_pane.grid(columnspan=1, row = 9, column=1, sticky='NW')
# ROW 8
self.display1 = tk.Text(master, wrap=tk.WORD)
self.display1.grid(columnspan=1, row = 10, column=1, sticky=tk.W)
def dataOps(self):
return(1)
def chooseSite(self):
return(1)
def pullSite(self):
return(1)
def sendEmail(self):
return(1)
root = tk.Tk()
root.geometry('800x800')
root["bg"] = "#ffffff"
my_gui = GUI(root)
root.mainloop()
I want to create a GUI with Tkinter, such that you are at a grocery store, you enter the item, price, and quantity, and each item will appear on the top part of the screen.
I have a top and bottom frame, and when I place an entry it goes right in the middle of the bottom frame. I have tried justifying the position to the left, anchoring it, sticking it and doing whatever, but it's not moving.
This is my code.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
actual = MenuBoard(root)
root.mainloop()
-Use
bottomFrame.grid_propagate(False)
to expand the frame and
storeItemEntry.grid(pady=30)
Or whatever value you want for pady. You might have to give row and column numbers to grid() if you're going to place other widgets in bottomFrame.
You saw "a strange dark grey background" as mentioned in the comment because you gave bg = "grey" to bottomFrame. The background wasn't visible initially because the frame shrank to fit the Entry. You can change the color to what you want or remove it entirely.
The following should be close to what you're looking for:
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), textvariable=textInput, bd =4)
storeItemEntry.grid(pady=30)
actual = MenuBoard(root)
root.mainloop()
UPDATE:
Based on your comments, here is a rough implementation to work with.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
mainFrame.grid_propagate(False)
mainFrame.grid_columnconfigure(0, weight=1)
heading = " Store Item".ljust(45)[:45] + "Item Price" # Pad the text with white spaces
listHeading = Label(mainFrame, text=heading, anchor="w", font=("Courier New",14,"bold"))
listHeading.grid(row=1, column=0, pady=5, stick="we")
# Use Text widget so you can keep inserting items
self.listItems = Text(mainFrame, font=("Courier New",12))
self.listItems.grid(row=2, column=0, pady=5, stick="we")
self.listItems.config(state="disabled") # Prevents edits on the Text
welcomeLabel = Label(mainFrame, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0, stick="we")
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemLabel = Label(bottomFrame, text="Food Item: ")
storeItemLabel.grid(row=0, column=0)
self.storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.storeItemEntry.grid(row=0, column=1, pady=15)
priceLabel = Label(bottomFrame, text="Price: ")
priceLabel.grid(row=2, column=0)
self.priceEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.priceEntry.grid(row=2, column=1,)
btn = Button(bottomFrame, text="Add Item", command=self.add)
btn.grid(row=3, column=1, pady=15)
def add(self):
price = self.storeItemEntry.get() # Get item name from Entry
#Get price, format name and price
groceryItem = price.ljust(50)[:50] + "$%s" %(self.priceEntry.get())
self.listItems.config(state="normal") # Enable edits on the Text
self.listItems.insert("end", "\n "+groceryItem) # Edit Text
self.listItems.config(state="disabled") # Prevents edits on the Text
actual = MenuBoard(root)
root.mainloop()
A couple of things to note:
I removed some of your frames because they seemed redundant, you can add them back if needed.
Since you're working with a class, I added the self keyword to some of the attributes so I can use/call them later in other methods without errors. I left out the attributes that I do not need to call after creation.
StringVar/textvariable is not needed since you're updating the list with a button click.
There are lots of refinements I did not do (i.e. checking to see if a valid input is given before updating the list, ability to delete from the list, etc).
I used methods and features that you may or may not be aware of (.ljust(50)[:50], %s, etc)
I hope this helps :).
First time here so forgive me as this is my FIRST attempt at making a silly GUI game (if you want to call it that). I'm trying to get the user to click a button and the image of their selection pops up. I can't seem to figure out how to get the image to pop up though.
Image does show if I run it separately.
My code:
from Tkinter import *
root = Tk()
class PokemonClass(object):
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.WelcomeLabel = Label(root, text="Welcome! Pick your Pokemon!",
bg="Black", fg="White")
self.WelcomeLabel.pack(fill=X)
self.CharButton = Button(root, text="Charmander", bg="RED", fg="White",
command=self.CharClick)
self.CharButton.pack(side=LEFT, fill=X)
self.SquirtButton = Button(root, text="Squirtle", bg="Blue", fg="White")
self.SquirtButton.pack(side=LEFT, fill=X)
self.BulbButton = Button(root, text="Bulbasaur", bg="Dark Green",
fg="White")
self.BulbButton.pack(side=LEFT, fill=X)
def CharClick(self):
print "You like Charmander!"
global CharSwitch
CharSwitch = 'Yes'
CharSwitch = 'No'
if CharSwitch == 'Yes':
CharPhoto = PhotoImage(file="Charmander.gif")
ChLabel = Label(root, image=CharPhoto)
ChLabel.pack()
k = PokemonClass(root)
root.mainloop()
This works, but the actual image no longer shows, if I keep the PhotoImage OUT of the class it will print but I want to have it print IF they click the specific button:
from Tkinter import *
root = Tk()
class PokemonClass(object):
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.WelcomeLabel = Label(root, text = "Welcome! Pick your Pokemon!", bg = "Black", fg = "White")
self.WelcomeLabel.pack(fill = X)
self.CharButton = Button(root, text = "Charmander", bg = "RED", fg = "White", command = CharClick)
self.CharButton.pack(side = LEFT, fill = X)
self.SquirtButton = Button(root, text = "Squirtle", bg = "Blue", fg = "White")
self.SquirtButton.pack(side = LEFT, fill = X)
self.BulbButton = Button(root, text = "Bulbasaur", bg = "Dark Green", fg = "White")
self.BulbButton.pack(side = LEFT, fill = X)
def CharClick():
print "You like Charmander!"
CharPhoto = PhotoImage(file = "Charmander.gif")
ChLabel = Label(root, image = CharPhoto)
ChLabel.pack()
k = PokemonClass(root)
root.mainloop()
You need to maintain a reference to your PhotoImage object. Unfortunately there is an inconsistency in tkinter in that attaching a Button to a parent widget increments the reference count, but adding an image to a widget does not increment the reference count. As a consequence at the moment the CharPhoto variable goes out of scope at the end of the function CharClick, the number of reference to the PhotoImage falls to zero and the object is made available for garbage collection.
If you keep a reference to the image somewhere, it will appear. When you kept it globally it remained in scope for the entire script and hence appeared.
You can keep a reference to it in the PokemonClass object or in the Label widget.
Below is the later of those options
from Tkinter import *
root = Tk()
class PokemonClass(object):
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.WelcomeLabel = Label(root, text="Welcome! Pick your Pokemon!",
bg="Black", fg="White")
self.WelcomeLabel.pack(fill=X)
self.CharButton = Button(root, text="Charmander", bg="RED", fg="White",
command=self.CharClick)
self.CharButton.pack(side=LEFT, fill=X)
self.SquirtButton = Button(root, text="Squirtle", bg="Blue", fg="White")
self.SquirtButton.pack(side=LEFT, fill=X)
self.BulbButton = Button(root, text="Bulbasaur", bg="Dark Green",
fg="White")
self.BulbButton.pack(side=LEFT, fill=X)
def CharClick(self):
print "You like Charmander!"
global CharSwitch
CharSwitch = 'Yes'
CharPhoto = PhotoImage(file="Charmander.gif")
ChLabel = Label(root, image=CharPhoto)
ChLabel.img = CharPhoto
ChLabel.pack()
CharSwitch = 'No'
k = PokemonClass(root)
root.mainloop()
The solution which helped me is just simply declaring all the image variables on the next line after 'root = Tk()'. Doing so won't spoil your code or anything.