I'm trying to make a basic GUI using Tkinter and have an entry box next to my label using a Grid manager, but the window is not showing when I run my program if I use .grid() with my Entry object.
It does work when I use .pack(), which is strange because I heard not to use .pack() when I have other things using .grid() in the same widget. But I do want to use .grid() because I want to be able to organize it how I want to.
Code is below, I'm having trouble with Entry object showName. The commented out .pack() statement is the one that does work, the .grid() statement is the one that does not work.
Does anybody know what's wrong with this?
from Tkinter import *
class RenamerGUI():
def __init__(self, master):
frame = Frame(master)
frame.pack() #Make frame visible
self.exit = Button(frame, text = "Exit", fg = "red", command = frame.quit)
self.csv2tsv = Button(frame, text = "csv2tsv", fg = "green", bg = "black", command=self.csv2tsv)
self.epguidestsvFormatter = Button(frame, text = "epguidestsvFormatter", fg = "green", bg = "black", command = self.epguidestsvFormatter)
self.epNamesList = Button(frame, text = "epNamesList", fg = "green", bg = "black", command = self.epNamesList)
self.SeasonSplitter = Button(frame, text = "SeasonSplitter", fg = "green", bg = "black", command = self.SeasonSplitter)
self.Renamer = Button(frame, text = "Renamer", fg = "green", bg = "black", command = self.Renamer)
self.showLabel = Label(frame, text = "Show: ")
self.showName = Entry(master)
self.get = Button(frame, text = "Get", command = self.textgetter)
self.exit.grid(row=3, column=4)
self.csv2tsv.grid(row=1, column = 0)
self.epguidestsvFormatter.grid(row=1, column=1)
self.epNamesList.grid(row=1, column=2)
self.SeasonSplitter.grid(row=1, column=3)
self.Renamer.grid(row=1, column=4)
self.showLabel.grid(row=2)
self.showName.grid(row=2, column=1)
#self.showName.pack(side=BOTTOM)
The entry has the wrong parent:
self.showName = Entry(master)
should be
self.showName = Entry(frame)
Related
I've managed to find a post on SO on how to create a Tkinter entry with a default value (referring to this one). The code below demonstrates my use of it:
comCurrent_Label = tk.Entry(root, font = (16), bg = "black", fg = "white", bd = 3, relief = "sunken")
comCurrent_Label.insert(0, ">>> ")
comCurrent_Label.grid(row = 2, column = 0, ipady = 15, ipadx = 175)
But I'd want for the user to be unable to delete >>> by backspacing too far.
My question is: How to make that entry's default text unchangeable/undeletable?
You can use the entry widget's validation feature to prevent the user from deleting the leading characters. Simply require that any new value begin with the string ">>> ", and the entry will prevent the user from deleting those characters.
Here's an example:
import tkinter as tk
def validate(new_value):
return new_value.startswith(">>> ")
root = tk.Tk()
vcmd = root.register(validate)
entry = tk.Entry(root, validate="key", validatecommand=(vcmd, "%P"))
entry.pack(side="top", fill="x", padx=20, pady=20)
entry.insert(0, ">>> ")
root.mainloop()
For a more in-depth explanation of entry validation see Interactively validating Entry widget content in tkinter
The easiest solution to this is to just put the >>> in a different widget, like a Label:
import tkinter as tk
root = tk.Tk()
subframe = tk.Frame(root, bd = 3, relief = "sunken")
lbl = tk.Label(subframe, text=">>> ", font = (16), bg = "black", fg = "white", bd=0, highlightthickness=0)
lbl.pack(side=tk.LEFT)
comCurrent_Label = tk.Entry(subframe, font = (16), bg = "black", fg = "white", bd=0, highlightthickness=0)
comCurrent_Label.pack(side=tk.LEFT)
subframe.grid(row = 2, column = 0, pady = 15, padx = 175)
root.mainloop()
You should probably wrap that up in a neat little subclass.
I'm trying to add an image in a Top Level window in python, however I can't seem to get it working.
I've tried using canvases and following some other steps on stack overflow. One thing I haven't tried is using class, init and self, but I don't really understand that, and hoping I can acheive my thing without the use of self. and stuff like that :D.
def pika():
def close():
win.destroy()
win = Toplevel()
win.geometry("150x150")
win.title("I CHOOSE U")
yellowb = Label(win, bg = 'yellow', fg = 'yellow', padx = 100, pady = 100)
yellowb.pack()
poke = PhotoImage(file = "pika.gif")
pika = Label(image = poke) # REEEEEEEEEEEEEEEEEE IT NO WORKEY
pika.grid(row = 0, column=1, padx = 10, pady = 10)
button = Button(win, text = "Close", command = close)
button.place(x=49, y=130)
Heres the main windows code
win = Tk()
win.geometry("290x200")
win.title('Error')
text1 = Label(win, bg= "Cyan", fg = 'Teal', padx = 50, pady = 75, text = '#hash error',
font = ('Times', '40', 'bold'))
text1.place(x=win.winfo_width() / 2, y=win.winfo_width() / 2)
button1 = Button(win, text = 'green', command = green)
button1.place(x=40, y=160)
button2 = Button(win, text = 'blue', command = blue)
button2.place(x=90, y=160)
button3 = Button(win, text = "red", command = red)
button3.place(x=130, y=160)
button4 = Button(win, text = 'yellow', command = yellow)
button4.place(x=170, y=160)
button5 = Button(win, text = "orange", command = orange)
button5.place(x=229, y=160)
eggs = PhotoImage(file = "pika.gif")
eggpic = Button(win, image = eggs, bg = 'Cyan', fg = 'Cyan', command = pika)
eggpic.place(x=100, y=20)
def close():
win.destroy()
closebut = Button(win, text='close', command = close)
closebut.place(x=0, y=0)
When I click a button and it opens a new windows the bg of the windows is yellow and everything as intended, however the image doesn't appear on the windows, and a white box the size of the image appears in the main tk window.
https://imgur.com/a/XU5m3Se
You can have two problems:
First: Every widget needs parent. If you don't use it then tkinter assigs widget to main window.
And you have this problem in Label(image = poke) because you forgot win in
pika = Label(win, image=poke)
This is why you see rectangle in main window instead of toplevel window.
Second: There is bug in PhotoImage. Garbage Collector removes it from memory when it is created in function and assigned to local variable. And then you can see empty image.
You have to assign PhotoImage to global variable or assign to other widget in function.
Popular solution with assigning to other widget:
poke = PhotoImage(file = "pika.gif")
pika = Label(win, image=poke)
pika.photo = poke # <-- assign PhotoImage to other widget too
More: PhotoImage
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.
I'm trying to get all of my labels and input boxes to be shifted down to the middle of the screen using the .pack() method. I tried using
anchor = CENTER
with the.place() method but that made everything overlap in the center. How can I simply shift all of my widgets to the center of my Tkinter frame?
Here's my code:
from Tkinter import *
root = Tk()
root.minsize(width = 500, height = 500)
root.wm_title("Email Program v1.0")
def callback():
print ("Hello!")
#sign in - email
usernameLabel = Label(root, text = "Email:")
usernameLabel.pack(padx = 0, pady = 0)
usernameInput = Entry(root)
usernameInput.pack()
usernameInput.focus_set()
passwordLabel = Label(root, text = "Password:")
passwordLabel.pack()
passwordInput = Entry(root, show = "*", width = 20)
passwordInput.pack()
passwordInput.focus_set()
#submit email credentials - connect to the server
submitEmail = Button(root, text = "Submit", fg = "black", width = 10, command = callback)
submitEmail.pack()
root.mainloop()
I managed to put those labels and entries to the center using three frames, two without any content just to 'eat' space.
frame1 = Frame(root)
frame1.pack(expand=True)
frame2 = Frame(root)
usernameLabel = Label(frame2, text = "Email:")
usernameLabel.pack(padx = 0, pady = 0)
usernameInput = Entry(frame2)
usernameInput.pack()
usernameInput.focus_set()
passwordLabel = Label(frame2, text = "Password:")
passwordLabel.pack()
passwordInput = Entry(frame2, show = "*", width = 20)
passwordInput.pack()
passwordInput.focus_set()
submitEmail = Button(frame2, text = "Submit", fg = "black", width = 10, command\
= callback)
submitEmail.pack()
frame2.pack(anchor=CENTER)
frame3 = Frame(root)
frame3.pack(expand=True)
The simple solution is to put all the widgets in a frame, and then center the frame.
i am doing a project in python in tkinter, to find out you age. in one line it says can't assign function to call. here is the line:
int(y_born_in) = Entry(window, width=20, bg="yellow", foreground = "purple", font = "X-Files")
( i got bored so i added fonts & stuff)
here is my actual code if you need it:
from tkinter import *
#key press function:
def click():
output.delete(0.0, END)
output.insert (2014 - int(y_born_in))
output.insert ("\n or it could be")
output.insert ( 2015 - int(y_born_in))
#code for the enter button
def enter_click(Event):
output.delete(0.0, END)
output.insert (2014 - int(y_born_in))
output.insert ("\n or it could be")
output.insert ( 2015 - int(y_born_in))
#collect text from text entry box
window = Tk()
window.title("how old are you?")
window.configure(background = "cyan")
#create label:
Label(window, text="please insert the year you were born", background = "hot pink",foreground = "light green", font = "X-Files") .grid( sticky=N)
#create text entry box
int(y_born_in) = Entry(window, width=20, bg="yellow", foreground = "purple", font = "X-Files")
y_born_in.grid(row=1, column=0,sticky=N)
#add a submit button
submit = Button(window, text="SUBMIT", width=6, command=click, background = "purple", fg = "yellow", font = "X-Files") .grid( sticky=N)
#create another label
Label(window, text="you were born in the year", background = "blue", foreground = "red", font = "X-Files") .grid( sticky=N)
#create text box
output = Text(window, width=75, height=8, wrap=WORD, background="coral", fg = "blue", font = "X-Files")
output.grid( sticky=N)
#enter key works as the button
window.bind("<Return>", enter_click )
window.mainloop()
You can't call int on the left side of an assignment statement. Instead, just do:
y_born_in = Entry(window, width=20, bg="yellow", foreground = "purple", font = "X-Files")
If you're trying to tell the program, "y_born_in should be an Entry that only accepts digits for input", that's a bit trickier. See Interactively validating Entry widget content in tkinter or Adding validation to an Entry widget for details.
Additionally, everywhere that you're trying to do int(y_born_in) to get what the user typed (like in click or enter_click), you should instead be doing int(y_born_in.get()).