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 :).
Related
i am doing a project to calculate the charges for different weight of the parcel. however, the position of the component(label, button, textbox and scrolltext) did not place it in the manner i want.
i want the length label to be in the center top, and the length textbox next to it. similar to width label and height label.
the following is my code.
from tkinter import *
import tkinter.scrolledtext as st
class Delivery(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Delivery Charges Calculator(Ong Jia Sheng)")
self.master.geometry("700x350") #width by height dimension
#create the components
#create RadioButtons
self._salute = StringVar() #common variable for Radio buttons
self._rb1 = Radiobutton(self,text="cm",variable=self._salute,value="cm")
self._rb2 = Radiobutton(self,text="inch",variable=self._salute,value="inch")
self._salute.set("cm") #value of radiobutton, this is to set default selection
#create other components
self._lenLb = Label(self, text="Length:")
self._widLb = Label(self, text="Width:")
self._heiLb = Label(self, text="Height:")
self._weiLb = Label(self, text="Weight(kg):")
self._lenTb = Entry(self, width=25)
self._widTb = Entry(self, width=25)
self._heiTb = Entry(self, width=25)
self._weiTb = Entry(self, width=25)
self._charButt = Button(self, width=15, text="Calculate Charge",command=self.calcCharges)
self._cleButt = Button(self, width=15,text="Clear",command=self.Clear)
self._stxt = st.ScrolledText(self,width=700,height=5)
#place onto the window use grid layout
self._lenLb.grid(row=0,column=4)
self._lenTb.grid(row=0,column=5)
self._widLb.grid(row=1,column=4)
self._widTb.grid(row=1,column=5)
self._heiLb.grid(row=2,column=4)
self._heiTb.grid(row=2,column=5)
self._rb1.grid(row=5,column=6)
self._rb2.grid(row=5,column=7)
self._weiLb.grid(row=8,column=4)
self._weiTb.grid(row=8,column=5)
self._charButt.grid(row=9,column=5)
self._cleButt.grid(row=9,column=6)
self._stxt.grid(row=9,column=0)
self.grid()
def calcCharges(self):
self._salute.set("inch")
def Clear(self):
self._salute.set("cm")
def main():
app = Delivery()
app.mainloop()
main()
The width of ScrolledText constructor is expressed in characters (not in pixels).
Since it is very wide (700 char) and alone in the first column, other widgets are moved far to the right and outside the screen.
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()
from tkinter import *
import tkinter as tk
class dashboard(Frame):
def __init__(self, master):
super(dashboard, self).__init__(master)
self.grid()
self.buttons()
def buttons(self):
#student dashboard button
bttn1 = Button(self, text = "Student",
command=self.student, height = 2, width= 15)
bttn1.grid()
#teacher dashboard button
bttn2 = Button(self, text = "Teacher", height = 2, width= 15)
bttn2.grid()
#exit button
bttn3 = Button(self, text = "Exit",
command=root.destroy, height = 2, width= 15)
bttn3.grid()
def student(self):
#view highscores button
bttn1 = Button(self, text = "Highscores", height = 2, width= 15)
bttn1.grid()
#print score button
bttn2 = Button(self, text = "Print Score", height = 2, width= 15)
bttn2.grid()
#exit button
bttn3 = Button(self, text = "Main Menu",
command=root.destroy, height = 2, width= 15)
bttn3.grid()
#main
root = Tk()
root.title("Dashboard")
root.geometry("300x170")
app = dashboard(root)
root.mainloop()
Wondered if someone could help me basically, with this GUI I am creating I want to be able to access a new page on the same frame but the buttons from the main menu stay once I go to another page, does anyone know how I can hide/forget the buttons and go back to them at a later stage? Thanks.
Updated to use sub-Frames
You could do it using the universal grid_remove() method (here's some documentation). One way to use it would be to keep references to each of the Button widgets created so you can call this method on them as needed.
However that can be simplified slightly—even though it takes about the same amount of code—by putting all the Buttonss for each page into a separate sub-Frame and just showing or hiding it which will automatically propagate do to all the widgets it contains. This approach also provides a better foundation for the rest of your program.
I've implemented this by adding a main_button_frame attribute to your class, as well as one named student_button_frame to hold those you have on the student page (since you'll probably need it to hide them too).
One nice thing about grid_remove() is that if you later call grid() on the same widget, it will remember all the settings it (and its sub-widgets) had before it was removed, so you don't need to create and maintain a list of every single one of them yourself.
Also note I also made some general modifications to your code so it conforms to the PEP 8 - Style Guide for Python Code recommendations better. I highly recommend you read and start following it.
from tkinter import *
import tkinter as tk
class Dashboard(Frame):
def __init__(self, master):
super().__init__(master)
self.grid()
self.main_button_frame = None
self.student_button_frame = None
self.create_main_buttons()
def create_main_buttons(self):
if self.student_button_frame: # Exists?
self.student_button_frame.grid_remove() # Make it invisible.
if self.main_button_frame: # Exists?
self.main_button_frame.grid() # Just make it visible.
else: # Otherwise create it.
button_frame = self.main_button_frame = Frame(self)
button_frame.grid()
# Student Dashboard button
bttn1 = Button(button_frame, text="Student",
command=self.create_student_buttons, height=2,
width=15)
bttn1.grid()
# Teacher Dashboard button
bttn2 = Button(button_frame, text="Teacher", height=2, width=15)
bttn2.grid()
# Dashboard Exit button
bttn3 = Button(button_frame, text="Exit", command=root.destroy,
height=2, width=15)
bttn3.grid()
def create_student_buttons(self):
if self.main_button_frame: # Exists?
self.main_button_frame.grid_remove() # Make it invisible.
if self.student_button_frame: # Exists?
student_button_frame.grid() # Just make it visible.
else: # Otherwise create it.
button_frame = self.student_button_frame = Frame(self)
button_frame.grid()
# Highscores button
bttn1 = Button(button_frame, text="Highscores", height=2, width=15)
bttn1.grid()
# Print Score button
bttn2 = Button(button_frame, text="Print Score", height=2, width=15)
bttn2.grid()
# Student Exit button
bttn3 = Button(button_frame, text="Exit", command=root.destroy,
height=2, width=15)
bttn3.grid()
# main
root = Tk()
root.title("Dashboard")
root.geometry("300x170")
app = Dashboard(root)
root.mainloop()
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()
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.