Related
If I run the following code alone, it displays the text in the grid while running:
def solve_wumpus_world(master, world_file):
world = World()
world.generate_world(world_file)
label_grid = [[Grid_Label(master, i, j) for j in range(world.num_cols)] for i in range(world.num_rows)]
agent = Agent(world, label_grid)
# Agent Solving
while agent.exited == False:
agent.explore()
if agent.found_gold == True:
agent.leave_cave()
break
agent.repaint_world()
agent.world_knowledge[agent.world.agent_row][agent.world.agent_col].remove('A')
time.sleep(1.5)
agent.repaint_world()
# GUI
def aigui():
game = Tk()
game.title("Hunt the Wumpus")
game.configure(bg="DarkOrchid4")
game.geometry("2000x2000")
game.iconbitmap(r'Images\Monster.ico')
world = World()
world.generate_world("world_1.txt")
grid = LabelFrame(game, text="GRID", fg="lawn green", bg="DarkOrchid4", padx=10, pady=10, font="Creepster 24")
worldLabel = LabelFrame(game, text="MENU", fg="lawn green", bg="DarkOrchid4", padx=10, pady=10, font="Creepster 20")
label_grid = [[Grid_Label(grid, i, j) for j in range(world.num_cols)] for i in range(world.num_rows)]
world_1 = Button(worldLabel, text="WORLD ONE", command=lambda: solve_wumpus_world(grid, "world_1.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_2 = Button(worldLabel, text="WORLD TWO", command=lambda: solve_wumpus_world(grid, "world_2.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_3 = Button(worldLabel, text="WORLD THREE", command=lambda: solve_wumpus_world(grid, "world_3.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_4 = Button(worldLabel, text="WORLD FOUR", command=lambda: solve_wumpus_world(grid, "world_4.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
quitButton = Button(worldLabel, text="QUIT", padx=40, font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green",
borderwidth=0, activeforeground="chartreuse2", activebackground="Indigo", command=lambda:game.destroy())
grid.pack(padx=1,pady=1)
worldLabel.pack(padx=5, pady=5)
world_1.grid(row=0, column=0, padx=10, pady=10, sticky=EW)
world_2.grid(row=0, column=1, padx=10, pady=10, sticky=EW)
world_3.grid(row=0, column=2, padx=10, pady=10, sticky=EW)
world_4.grid(row=0, column=3, padx=10, pady=10, sticky=EW)
quitButton.grid(row=1, column=1, columnspan=2, padx=10, pady=10, sticky=EW)
game.mainloop()
It shows the text inside the grid when gaming is being played
But when I call the above code from another class like a main class which has a main menu which further opens this game window, the game works fine and the boxes are also highlighted but the text isn't displayed. For example, the code below
def solve_wumpus_world(master, world_file):
world = World()
world.generate_world(world_file)
label_grid = [[Grid_Label(master, i, j) for j in range(world.num_cols)] for i in range(world.num_rows)]
agent = Agent(world, label_grid)
# Agent Solving
while agent.exited == False:
agent.explore()
if agent.found_gold == True:
agent.leave_cave()
break
agent.repaint_world()
agent.world_knowledge[agent.world.agent_row][agent.world.agent_col].remove('A')
time.sleep(1.5)
agent.repaint_world()
# GUI
def aigui():
game = Tk()
game.title("Hunt the Wumpus")
game.configure(bg="DarkOrchid4")
game.geometry("2000x2000")
game.iconbitmap(r'Images\Monster.ico')
world = World()
world.generate_world("world_1.txt")
grid = LabelFrame(game, text="GRID", fg="lawn green", bg="DarkOrchid4", padx=10, pady=10, font="Creepster 24")
worldLabel = LabelFrame(game, text="MENU", fg="lawn green", bg="DarkOrchid4", padx=10, pady=10, font="Creepster 20")
label_grid = [[Grid_Label(grid, i, j) for j in range(world.num_cols)] for i in range(world.num_rows)]
world_1 = Button(worldLabel, text="WORLD ONE", command=lambda: solve_wumpus_world(grid, "world_1.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_2 = Button(worldLabel, text="WORLD TWO", command=lambda: solve_wumpus_world(grid, "world_2.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_3 = Button(worldLabel, text="WORLD THREE", command=lambda: solve_wumpus_world(grid, "world_3.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
world_4 = Button(worldLabel, text="WORLD FOUR", command=lambda: solve_wumpus_world(grid, "world_4.txt"), padx=40,
font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green", borderwidth=0,
activeforeground="chartreuse2", activebackground="Indigo")
quitButton = Button(worldLabel, text="QUIT", padx=40, font="Leichenhaus 16 bold", bg="DarkViolet", fg="lawn green",
borderwidth=0, activeforeground="chartreuse2", activebackground="Indigo", command=lambda:game.destroy())
grid.pack(padx=1,pady=1)
worldLabel.pack(padx=5, pady=5)
world_1.grid(row=0, column=0, padx=10, pady=10, sticky=EW)
world_2.grid(row=0, column=1, padx=10, pady=10, sticky=EW)
world_3.grid(row=0, column=2, padx=10, pady=10, sticky=EW)
world_4.grid(row=0, column=3, padx=10, pady=10, sticky=EW)
quitButton.grid(row=1, column=1, columnspan=2, padx=10, pady=10, sticky=EW)
game.mainloop()
def maingui():
root = Tk()
root.geometry("600x600")
root.title("Hunt the Wumpus - Game")
root.configure(bg="DarkOrchid4")
root.iconbitmap(r'Images\Monster.ico')
# Label
myLabel = LabelFrame(root, text="Hunt the Wumpus", fg="lawn green", bg="DarkOrchid4", padx=100, pady=100)
textFont = ("Creepster", 24)
myLabel.config(font=textFont)
# Functions
# Buttons
buttonFont = ("Leichenhaus", 16)
aiButton = Button(myLabel, text="GAME", fg="lawn green", bg="DarkViolet",
activeforeground="chartreuse2", activebackground="Indigo", padx=40, command=aigui)
aiButton.config(font=buttonFont)
creditButton = Button(myLabel, text="Credits", fg="lawn green", bg="DarkViolet",
activeforeground="chartreuse2", activebackground="Indigo", padx=40)
creditButton.config(font=buttonFont)
quitButton = Button(myLabel, text="Quit", fg="lawn green", bg="DarkViolet",
activeforeground="chartreuse2", activebackground="Indigo", padx=40, command=lambda: root.destroy())
quitButton.config(font=buttonFont)
# Packing on Screen
myLabel.pack(padx=10, pady=10)
aiButton.grid(row=0, column=2, padx=10, pady=10, sticky=EW)
creditButton.grid(row=1, column=2, padx=10, pady=10, sticky=EW)
quitButton.grid(row=3, column=2, padx=10, pady=10, sticky=EW)
root.mainloop()
maingui()
This code calls the above code from a method when the button is pressed.
Text not being displayed but the game is working fine.
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 1 year ago.
from tkinter import *
from tkinter import ttk
from PIL import ImageTk ,Image
win=tkinter.Toplevel()
wrapper=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper.place(x=0, y=80, width=465, height=625)
wrapper3=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper3.place(x=950, y=80, width=465, height=625)
wrapper3_title=Label(wrapper3, text="Selected Data", bg="crimson", fg="white", font=("times new roman",30,"bold"))
wrapper3_title.grid(row=0,column=0,padx=20, pady=10)
wrapper2=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper2.place(x=465, y=80, width=485, height=625)
ent8=StringVar()
def code():
btn1.destroy()
add=StringVar()
sub=StringVar()
pro=StringVar()
img=ImageTk.PhotoImage(Image.open("Amritsar.jpg"))
Label2= Label(wrapper2, image=img)
Label2.grid(row=0, column=0, padx=10, pady=5, sticky='w')
def Find():
add.set(float(ent00.get())+float(ent01.get()))
sub.set(float(ent00.get())-float(ent01.get()))
pro.set(float(ent00.get())*float(ent01.get()))
ent00=Entry(wrapper, width=15)
ent00.grid(row=4, column=1, padx=10, pady=10, sticky='w')
ent01=Entry(wrapper, width=15)
ent01.grid(row=5, column=1, padx=10, pady=10, sticky='w')
lbl8=Label(wrapper, text="Add", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=6, column=0, padx=20, pady=10, sticky='w')
ent8=Entry(wrapper, textvariable=add, width=15, state='readonly')
ent8.grid(row=6, column=1, padx=10, pady=10, sticky='w')
lbl15=Label(wrapper, text="Subtract", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=7, column=0, padx=20, pady=10, sticky='w')
ent15=Entry(wrapper, textvariable=sub, width=15, state='readonly')
ent15.grid(row=7, column=1, padx=10, pady=10, sticky='w')
lbl9=Label(wrapper, text="Product", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=8, column=0, padx=20, pady=10, sticky='w')
ent9=Entry(wrapper, textvariable=pro, width=15, state='readonly')
ent9.grid(row=8, column=1, padx=10, pady=10, sticky='w')
btn = Button(wrapper, text = 'Calculate', command=Find, bd = '5', width=15, height=2)
btn.grid(row=11, column=1, padx=20, pady=10)
def img():
if ent8.get()=="4":
img=ImageTk.PhotoImage(Image.open("Amritsar.jpg"))
Label2= Label(wrapper3, image=img)
Label2.grid(row=0, column=2, padx=10, pady=5, sticky='w')
print("Move ahead")
else:
print("Try again")
btn2 = Button(wrapper, text = 'Image', command=img, bd = '5', width=15, height=2)
btn2.grid(row=12, column=1, padx=20, pady=10)
btn1 = Button(wrapper, text = 'OPEN CODE', command=code, bd = '5', width=20, height=2)
btn1.grid(row=11, column=1, padx=20, pady=10)
win.geometry("1400x700+250+250")
win.mainloop()
Two images need to be shown on the tkinter. The one defined earlier in wrapper2, shows empty frame while the one that has to appear in wrapper3 after getting 4 as sum, does not appear at all. Moreover, the output printed is "Try again". Why it is so? When sum is 4 it has to show "Move ahead".
First of all, terrible names.
Both your function and your PhotoImage are named img. Rename the function to def add_img().
Second, looking at your code I have no idea what all the wrapper frames are for, why not name them according to what they are planned to hold? Same applies to all the widgets. Wouldn't calc_btn be a better name than btn? img_btn instead of btn2? Why do you need to read more than the name to know what something is?
Third, you have ent8 twice in your code. Once as Label and again as a StringVar.
Tkinter constantly refreshes your window so you need to save the image you are using.
Personally I would have done all of this in a class.
For right now, with your current code, just add
loaded_img = ImageTk.PhotoImage(Image.open("Amritsar.jpg")) before your functions and instead of using the variables you are using to open the image, just use Label(wrapper3, image=loaded_img)
As in:
win = Toplevel()
wrapper=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper.place(x=0, y=80, width=465, height=625)
wrapper3=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper3.place(x=950, y=80, width=465, height=625)
wrapper3_title=Label(wrapper3, text="Selected Data", bg="crimson", fg="white", font=("times new roman",30,"bold"))
wrapper3_title.grid(row=0,column=0,padx=20, pady=10)
wrapper2=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper2.place(x=465, y=80, width=485, height=625)
ent8=StringVar()
loaded_img = ImageTk.PhotoImage(Image.open("Amritsar.jpg"))
Edit
Here is the entire code:
from tkinter import *
from tkinter import ttk
from PIL import ImageTk ,Image
win=Toplevel()
wrapper=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper.place(x=0, y=80, width=465, height=625)
wrapper3=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper3.place(x=950, y=80, width=465, height=625)
wrapper3_title=Label(wrapper3, text="Selected Data", bg="crimson", fg="white", font=("times new roman",30,"bold"))
wrapper3_title.grid(row=0,column=0,padx=20, pady=10)
wrapper2=Frame(win, bd=4, relief=RIDGE, bg="crimson")
wrapper2.place(x=465, y=80, width=485, height=625)
ent8=StringVar()
loaded_img = ImageTk.PhotoImage(Image.open("Amritsar.jpg"))
add_strvar = StringVar()
sub_strvar = StringVar()
pro_strvar = StringVar()
def code():
btn1.destroy()
Label2= Label(wrapper2, image=loaded_img)
Label2.grid(row=0, column=0, padx=10, pady=5, sticky='w')
def Find():
add_strvar.set(float(ent00.get())+float(ent01.get()))
sub_strvar.set(float(ent00.get())-float(ent01.get()))
pro_strvar.set(float(ent00.get())*float(ent01.get()))
ent00=Entry(wrapper, width=15)
ent00.grid(row=4, column=1, padx=10, pady=10, sticky='w')
ent01=Entry(wrapper, width=15)
ent01.grid(row=5, column=1, padx=10, pady=10, sticky='w')
lbl8=Label(wrapper, text="Add", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=6, column=0, padx=20, pady=10, sticky='w')
ent8=Entry(wrapper, textvariable=add_strvar, width=15, state='readonly')
ent8.grid(row=6, column=1, padx=10, pady=10, sticky='w')
lbl15=Label(wrapper, text="Subtract", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=7, column=0, padx=20, pady=10, sticky='w')
ent15=Entry(wrapper, textvariable=sub_strvar, width=15, state='readonly')
ent15.grid(row=7, column=1, padx=10, pady=10, sticky='w')
lbl9=Label(wrapper, text="Product", bg="crimson", fg="white", font=("times new roman",15,"bold")).grid(row=8, column=0, padx=20, pady=10, sticky='w')
ent9=Entry(wrapper, textvariable=pro_strvar, width=15, state='readonly')
ent9.grid(row=8, column=1, padx=10, pady=10, sticky='w')
btn = Button(wrapper, text = 'Calculate', command=Find, bd = '5', width=15, height=2)
btn.grid(row=11, column=1, padx=20, pady=10)
def add_img():
if add_strvar.get() == "4.0":
Label2= Label(wrapper3, image=loaded_img)
Label2.grid(row=0, column=2, padx=10, pady=5, sticky='w')
print("Move ahead")
else:
print("Try again")
btn2 = Button(wrapper, text = 'Image', command=add_img, bd = '5', width=15, height=2)
btn2.grid(row=12, column=1, padx=20, pady=10)
btn1 = Button(wrapper, text = 'OPEN CODE', command=code, bd = '5', width=20, height=2)
btn1.grid(row=11, column=1, padx=20, pady=10)
win.geometry("1400x700+250+250")
win.mainloop()
Edit 2
Code changed to work with classes:
from tkinter import *
from tkinter import ttk
from PIL import ImageTk ,Image
class ImageCalculator:
def __init__(self, img_path):
self.window = Toplevel()
self.window.geometry("1400x700+250+250")
self.mainframe = Frame(self.window)
self.mainframe.pack(expand=True, fill=BOTH)
self.bg_color = 'crimson'
frame_settings = {'master': self.mainframe, 'bd': 4,
'relief': RIDGE, 'bg': self.bg_color}
frame_names = ('left', 'center', 'right')
self.frames = {name: Frame(**frame_settings) for name in frame_names}
frame_height = 625
init_y = 80
frame_widths = {'left': 465, 'center': 485, 'right': 465}
x = 0
for name in frame_names:
frame_width = frame_widths[name]
self.frames[name].place(x=x, y=init_y, width=frame_width,
height=frame_height)
x += frame_width
self.setup_right_wrapper()
self.code_btn = self.setup_left_wrapper()
self.loaded_image = ImageTk.PhotoImage(Image.open(img_path))
self.add_strvar = StringVar()
self.sub_strvar = StringVar()
self.pro_strvar = StringVar()
def setup_left_wrapper(self) -> Button:
code_btn = Button(self.frames['left'], text='OPEN CODE', command=self.code,
bd='5', width=20, height=2)
img_btn = Button(self.frames['left'], text='Image', bd='5', width=15,
height=2, command=self.add_img)
code_btn.grid(row=11, column=1, padx=20, pady=10)
img_btn.grid(row=12, column=1, padx=20, pady=10)
return code_btn
def setup_right_wrapper(self):
right_frame_title = Label(self.frames['right'], text="Selected Data",
bg=self.bg_color, fg="white",
font=("times new roman",30,"bold"))
right_frame_title.grid(row=0, column=0, padx=20, pady=10)
def code(self):
def Find():
self.add_strvar.set(float(first_entry.get())
+ float(second_entry.get()))
self.sub_strvar.set(float(first_entry.get())
- float(second_entry.get()))
self.pro_strvar.set(float(first_entry.get())
* float(second_entry.get()))
self.code_btn.destroy()
Label2 = Label(self.frames['center'], image=self.loaded_image)
Label2.grid(row=0, column=0, padx=10, pady=5, sticky='w')
left_frame = self.frames['left']
first_entry = Entry(left_frame, width=15)
second_entry = Entry(left_frame, width=15)
# Settings of all labels
lbl_settings = {'bg': self.bg_color, 'fg': 'white',
'font': ("times new roman", 15, "bold")}
# Setting of all entry.
entry_settings = {'width': 15, 'state': 'readonly'}
add_lbl = Label(left_frame, text="Add", **lbl_settings)
add_entry = Entry(left_frame, textvariable=self.add_strvar,
**entry_settings)
sub_lbl = Label(left_frame, text="Subtract", **lbl_settings)
sub_entry = Entry(left_frame, textvariable=self.sub_strvar,
**entry_settings)
pro_lbl = Label(left_frame, text="Product", **lbl_settings)
pro_entry = Entry(left_frame, textvariable=self.pro_strvar,
**entry_settings)
calc_btn = Button(left_frame, text='Calculate', command=Find, bd='5',
width=15, height=2)
# Widget placement.
first_entry.grid(row=4, column=1, padx=10, pady=10, sticky='w')
second_entry.grid(row=5, column=1, padx=10, pady=10, sticky='w')
add_lbl.grid(row=6, column=0, padx=20, pady=10, sticky='w')
add_entry.grid(row=6, column=1, padx=10, pady=10, sticky='w')
sub_lbl.grid(row=7, column=0, padx=20, pady=10, sticky='w')
sub_entry.grid(row=7, column=1, padx=10, pady=10, sticky='w')
pro_lbl.grid(row=8, column=0, padx=20, pady=10, sticky='w')
pro_entry.grid(row=8, column=1, padx=10, pady=10, sticky='w')
calc_btn.grid(row=11, column=1, padx=20, pady=10)
def add_img(self):
if self.add_strvar.get() == "4.0":
Label2 = Label(self.frames['right'], image=self.loaded_image)
Label2.grid(row=0, column=2, padx=10, pady=5, sticky='w')
print("Move ahead")
else:
print("Try again")
def main():
img_calc = ImageCalculator('Amritsar.jpg')
mainloop()
if __name__ == "__main__":
main()
After setting an image for a Label, you need to keep a reference to this image. Otherwise, it's removed at the end of the function and you lose the image (it's garbage collected).
So, when you define your label, just add a line that stores the image as an attribute of the label:
img=ImageTk.PhotoImage(Image.open("Amritsar.jpg"))
Label2= Label(wrapper2, image=img)
Label2.grid(row=0, column=0, padx=10, pady=5, sticky='w')
Label2.dontloseit = img
The Label2 widget now has a nonsensical attribute called .dontloseit which holds the image. Now, it won't get collected and it will show in your tkinter widget.
It's one of the peculiarities of tkinter.
This is my code:
mycanvas = Canvas(self.search_result_frame)
mycanvas.pack(side=LEFT)
yscrollbar = ttk.Scrollbar(self.search_result_frame, orient="vertical", command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill=Y)
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>', lambda e: mycanvas.configure(scrollregion = mycanvas.bbox('all')))
self.sample_frame = Frame(mycanvas)
mycanvas.create_window((0,0), window=self.sample_frame, anchor=E)
for widget in self.search_result_frame.winfo_children():
widget.destroy()
if len(matching_bills) > 0:
for bill in matching_bills:
with open(f'{self.bill_folder}//{bill}//data//bill_details.json', 'r') as bill_json_file:
bill_details = json.loads(bill_json_file.read())
customer_name = bill_details["customer_details"][0]
payment_method = bill_details["payment_method"]
date_of_issue = bill_details["date_of_issue"]
date_of_issue = datetime.strptime(date_of_issue, "%d/%m/%Y")
date_of_issue = date_of_issue.strftime("%d %b %Y")
# # -------------------- Search Result Frame Contents
result_frame = Frame(self.sample_frame, bg=self.bg3, bd=5, relief=GROOVE)
result_frame.pack(fill=BOTH, pady=2)
result_billno_lbl = Label(result_frame, text=bill, bg=self.bg1, fg="#FFF", font=self.search_results_font1, padx=22, pady=3)
result_billno_lbl.grid(row=0, column=0, padx=50, pady=8, sticky=W)
billed_to_lbl = Label(result_frame, text=f"Billed To - {customer_name}", bg=self.bg1, fg="#FFF", font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
billed_to_lbl.grid(row=0, column=1, padx=80, sticky=W)
billed_type_lbl = Label(result_frame, text=f"Bill Type - {payment_method}", bg=self.bg1, fg="#FFF", font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
billed_type_lbl.grid(row=0, column=2, sticky=W)
issued_on_lbl = Label(result_frame, text=f"Issued On - {date_of_issue}", bg=self.bg1, fg="#FFF",
font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
issued_on_lbl.grid(row=0, column=3, padx=80, sticky=W)
view_btn = Button(result_frame, text="View", font="Comicsan 14", bd=2, relief=GROOVE, bg="#000", fg="#FFF", padx=1, command=lambda bill=bill: self.view_bill(bill))
view_btn.grid(row=0, column=4, padx=3, columnspan=2, sticky=W)
elif len(matching_bills) == 0:
for widgets in self.search_result_frame.winfo_children():
widgets.destroy()
no_result_lbl = Label(self.search_result_frame, text=f"No search result found for {bill_cat}", font=self.search_results_font1, bg=self.bg3, fg="#FFF")
no_result_lbl.pack(fill=X)
When I run it, it shows me the bad window path name ".!labelframe.!canvas.!frame error and when I try to do the same thing without object-oriented in tkinter then it works well !
I want to create a BMI calculator program with Tkinter but I'm stuck at calculation procedure
I use StringVar() to keep user data to calculate but I don't know how to calculate
this my code :
from tkinter import *
def mainwindow():
main = Tk()
main.geometry("300x400")
main.title("BMI")
main.rowconfigure((0,1,2,3,4), weight=1)
main.columnconfigure(0, weight=1)
main.config(bg="green")
main.option_add("*Font", "times 15 bold")
return main
def createframe(main):
Label(main, text="BMI APP", bg="lightgreen").grid(row=0, column=0, sticky=N)
frame_1 = Frame(main, bg="white")
frame_1.grid(row=1, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_2 = Frame(main, bg="white")
frame_2.grid(row=2, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_3 = Frame(main, bg="white")
frame_3.grid(row=3, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom = Frame(main, bg="white")
frame_bottom.grid(row=4, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom.columnconfigure(0, weight=0)
frame_bottom.columnconfigure(1, weight=2)
return frame_1, frame_2, frame_3, frame_bottom
def widget(frame_1, frame_2, frame_3, frame_bottom):
Label(frame_1, text="HEIGHT:(cm.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_height = Entry(frame_1, bg="pink", textvariable=height_var)
ent_height.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_2, text="WEIGHT:(kg.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_weight = Entry(frame_2, bg="lightblue", textvariable=weight_var)
ent_weight.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Button(frame_bottom, text="Calculate", highlightbackground="lightgreen", fg="white", command=find_bmi).grid(row=2, column=1)
show_data = Label(frame_bottom, bg="white")
return ent_height, ent_weight
def find_bmi():
global bmi
bmi = 0
height = height_var.get()
weight = weight_var.get()
height = float(height) / 100.0
bmi = float(weight) / height ** 2
print("BMI = %0.2f" % bmi)
bmi = 0
main = mainwindow()
height_var = StringVar()
height_var.set("1")
weight_var = StringVar()
weight_var.set("1")
frame_1, frame_2, frame_3, frame_bottom = createframe(main)
ent_height, ent_weight = widget(frame_1, frame_2, frame_3, frame_bottom)
find_bmi()
main.mainloop()
I try to set a new value and calculate it because StringVar() can't calculate itself but when I use it that way I have to set the default to 1 if I don't set it will error ZeroDivisionError: float division by zero I don't want to set a number first if I set the first user will see that number
the frame_3 is used to show BMI to the user when calculating completed
You can check to see if the height and weight inputs have been filled in before doing the conversion/calculation.
from tkinter import *
def mainwindow():
main = Tk()
main.geometry("300x400")
main.title("BMI")
main.rowconfigure((0,1,2,3,4), weight=1)
main.columnconfigure(0, weight=1)
main.config(bg="green")
main.option_add("*Font", "times 15 bold")
return main
def createframe(main):
Label(main, text="BMI APP", bg="lightgreen").grid(row=0, column=0, sticky=N)
frame_1 = Frame(main, bg="white")
frame_1.grid(row=1, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_2 = Frame(main, bg="white")
frame_2.grid(row=2, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_3 = Frame(main, bg="white")
frame_3.grid(row=3, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom = Frame(main, bg="white")
frame_bottom.grid(row=4, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom.columnconfigure(0, weight=0)
frame_bottom.columnconfigure(1, weight=2)
return frame_1, frame_2, frame_3, frame_bottom
def widget(frame_1, frame_2, frame_3, frame_bottom):
Label(frame_1, text="HEIGHT:(cm.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_height = Entry(frame_1, bg="pink", textvariable=height_var)
ent_height.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_2, text="WEIGHT:(kg.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_weight = Entry(frame_2, bg="lightblue", textvariable=weight_var)
ent_weight.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_3, text="BMI").grid(row=0, column=0, padx=5, pady=5,sticky=W)
show_data = Label(frame_3)
show_data.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Button(frame_bottom, text="Calculate", highlightbackground="lightgreen", fg="white", command=find_bmi).grid(row=2, column=1)
return ent_height, ent_weight, show_data
def find_bmi():
height = height_var.get()
weight = weight_var.get()
# check height and weight filled in
if height and weight:
height = float(height) / 100.0
bmi = round(float(weight) / height ** 2, 2)
show_data.config(text = bmi)
else:
show_data.config(text='')
main = mainwindow()
height_var = StringVar()
weight_var = StringVar()
frame_1, frame_2, frame_3, frame_bottom = createframe(main)
ent_height, ent_weight, show_data = widget(frame_1, frame_2, frame_3, frame_bottom)
main.mainloop()
So I'm writing a program for my final year project, and this thing in particular has just been bugging the hell out of me. I've been at it so long and I can't figure it out, so I'm hoping somebody fresh will be able to shed some light on it!
Basically, my program is for recording and storing results for my school's sports day. The idea is that it will actually be used in the future by the school, so I want it to be aesthetic as well as functional. Of course, this means integrating a UI of some kind, and since I've used Tkinter before it seemed like the obvious approach.
So far I've just got the basic windows coded. I have two windows: a main window and an "edit" window for changing participant names. I've written the code for these two windows in separate .py files and imported the "edit" window file into the main file, so that I can call for it to run when an "EDIT" button is clicked in the main window. For whatever reason, however, the "edit" window simply runs itself when I run the main program, even though the only reference to it is import editWindow.
This is the code for the main window:
'''
Created on 19 Jan 2015
#author: James.D.Wood
'''
#!/usr/bin/env python
#init
from tkinter import *
import editWindow
global event, year, cr, sr, a1, a2, s1, s2, d1, d2, n1, n2, ar1, ar2, sr1, sr2, dr1, dr2, nr1, nr2, msg, b, s, g
events = [
"70m hurdles",
"75m hurdles",
"80m hurdles",
"100m hurdles",
"100m",
"200m",
"300m",
"400m",
"800m",
"1500m",
"Javelin",
"Long-jump",
"High-jump",
"Triple-jump",
"Shot-put",
"Discus",
"Relay"
]
years = [
"7",
"8",
"9",
"10",
"11",
"12",
"13"
]
#create/define window
#main win
win = Tk()
win.title("Queens' Athletics")
win.minsize(800,600)
win.maxsize(800,600)
#section 1
event = StringVar() #event var
event.set("Select event...") #default
year = StringVar() #year var
year.set("Select year...") #default
lineImg = PhotoImage(file="resources/line.gif", master=win) #load separator image
sel = Label(win, text="Select event:")
slctEvnt = OptionMenu(win, event, *events) #dropdown box
slctEvnt.config(width=20)
selYr = Label(win, text="Select year:")
slctYr = OptionMenu(win, year, *years) #dropdown box
slctYr.config(width=20)
line = Label(win, image=lineImg) #separator
line.image = lineImg
#pack into window
sel.grid(row=0, column=0, sticky=W)
slctEvnt.grid(row=0, column=1, columnspan=4, sticky=W)
selYr.grid(row=1, column=0, sticky=W)
slctYr.grid(row=1, column=1, columnspan=4, sticky=W)
line.grid(row=2, column=0, columnspan=4, sticky=W, pady=15)
#section 2
cr = StringVar() #county record var
cr.set(" - ") #default
sr = StringVar() #school record var
sr.set(" - ") #default
crl = Label(win, text="County record:")
crBox = Label(win, width=6, textvariable=cr, state='normal', relief='sunk', bg="grey") #county record box
srl = Label(win, text="School record:")
srBox = Label(win, width=6, textvariable=sr, state='normal', relief='sunk', bg="grey") #school record box
#pack into window
crl.grid(row=3, column=0, sticky=W)
crBox.grid(row=3, column=1, sticky=W, padx=10)
srl.grid(row=3, column=2, sticky=W)
srBox.grid(row=3, column=3, sticky=W, padx=10)
#section 3
#participant names
a1 = StringVar()
a1.set(". . .") #default
a2 = StringVar()
a2.set(". . .") #default
s1 = StringVar()
s1.set(". . .") #default
s2 = StringVar()
s2.set(". . .") #default
d1 = StringVar()
d1.set(". . .") #default
d2 = StringVar()
d2.set(". . .") #default
n1 = StringVar()
n1.set(". . .") #default
n2 = StringVar()
n2.set(". . .") #default
#results
ar1 = StringVar()
ar2 = StringVar()
sr1 = StringVar()
sr2 = StringVar()
dr1 = StringVar()
dr2 = StringVar()
nr1 = StringVar()
nr2 = StringVar()
#
vLineImg = PhotoImage(file="resources/vline.gif", master=win) #load separator image
blank1 = Label(win, text="") #blank separator
part = Label(win, text="Students participating:")
resul = Label(win, text=" Results")
#participant names
auden1 = Label(win, width=36, textvariable=a1, state='normal', relief='sunk', bg="yellow")
auden2 = Label(win, width=36, textvariable=a2, state='normal', relief='sunk', bg="yellow")
suthe1 = Label(win, width=36, textvariable=s1, state='normal', relief='sunk', bg="blue")
suthe2 = Label(win, width=36, textvariable=s2, state='normal', relief='sunk', bg="blue")
drake1 = Label(win, width=36, textvariable=d1, state='normal', relief='sunk', bg="green")
drake2 = Label(win, width=36, textvariable=d2, state='normal', relief='sunk', bg="green")
newto1 = Label(win, width=36, textvariable=n1, state='normal', relief='sunk', bg="red")
newto2 = Label(win, width=36, textvariable=n2, state='normal', relief='sunk', bg="red")
#results
auRes1 = Entry(win, width=12, textvariable=ar1, justify=CENTER, state='normal', relief='sunk', bg="yellow")
auRes2 = Entry(win, width=12, textvariable=ar2, justify=CENTER, state='normal', relief='sunk', bg="yellow")
suRes1 = Entry(win, width=12, textvariable=sr1, justify=CENTER, state='normal', relief='sunk', bg="blue")
suRes2 = Entry(win, width=12, textvariable=sr2, justify=CENTER, state='normal', relief='sunk', bg="blue")
drRes1 = Entry(win, width=12, textvariable=dr1, justify=CENTER, state='normal', relief='sunk', bg="green")
drRes2 = Entry(win, width=12, textvariable=dr2, justify=CENTER, state='normal', relief='sunk', bg="green")
neRes1 = Entry(win, width=12, textvariable=nr1, justify=CENTER, state='normal', relief='sunk', bg="red")
neRes2 = Entry(win, width=12, textvariable=nr2, justify=CENTER, state='normal', relief='sunk', bg="red")
#
vLine = Label(win, image=vLineImg)
vLine.image = vLineImg
#pack into window
blank1.grid(row=5)
part.grid(row=6, column=0, columnspan=2, sticky=W, pady=8)
resul.grid(row=7, column=3, sticky=W)
#participant names
auden1.grid(row=8, column=0, columnspan=3, sticky=W, padx=8)
auden2.grid(row=9, column=0, columnspan=3, sticky=W, padx=8)
suthe1.grid(row=10, column=0, columnspan=3, sticky=W, padx=8)
suthe2.grid(row=11, column=0, columnspan=3, sticky=W, padx=8)
drake1.grid(row=12, column=0, columnspan=3, sticky=W, padx=8)
drake2.grid(row=13, column=0, columnspan=3, sticky=W, padx=8)
newto1.grid(row=14, column=0, columnspan=3, sticky=W, padx=8)
newto2.grid(row=15, column=0, columnspan=3, sticky=W, padx=8)
#results
auRes1.grid(row=8, column=3, columnspan=2, sticky=W)
auRes2.grid(row=9, column=3, columnspan=2, sticky=W)
suRes1.grid(row=10, column=3, columnspan=2, sticky=W)
suRes2.grid(row=11, column=3, columnspan=2, sticky=W)
drRes1.grid(row=12, column=3, columnspan=2, sticky=W)
drRes2.grid(row=13, column=3, columnspan=2, sticky=W)
neRes1.grid(row=14, column=3, columnspan=2, sticky=W)
neRes2.grid(row=15, column=3, columnspan=2, sticky=W)
#
vLine.grid(row=8, column=4, rowspan=8, sticky=W, padx=35)
#section 4
msg = StringVar()
msg.set("[ ]")
edit = Button(win, width=8, text="Edit >", padx=15, pady=8)
submit = Button(win, width=8, text="Submit >", padx=15, pady=8)
msgBox = Message(win, textvariable=msg, anchor=CENTER, justify=CENTER, aspect=200, borderwidth=2, relief='ridge', bg='grey')
reset = Button(win, width=8, text="Reset >", padx=15, pady=8)
#pack into window
edit.grid(row=16, column=1, rowspan=2, sticky=S, pady=12)
submit.grid(row=16, column=3, rowspan=2, sticky=S, pady=12)
msgBox.grid(row=16, column=4, rowspan=2, columnspan=3, sticky=S, pady=16)
reset.grid(row=16, column=7, rowspan=2, sticky=S, pady=12)
#section 5
img = PhotoImage(file="resources/logo.gif", master=win)
logo = Label(win, image=img)
logo.image = img
logo.grid(row=0, column=4, rowspan=7, columnspan=4, sticky=W+E+N+S, padx=60, pady=5)
#section 6
#leading participants
b = StringVar()
b.set(". . .") #default
s = StringVar()
s.set(". . .") #default
g = StringVar()
g.set(". . .") #default
stand = Label(win, text="Current standing:")
first = Label(win, text="1st")
secon = Label(win, text="2nd")
third = Label(win, text="3rd")
#leading participants
bron = Label(win, width=20, height=2, textvariable=b, state='normal', relief='sunk', bg="brown")
silv = Label(win, width=20, height=2, textvariable=s, state='normal', relief='sunk', bg="lightgrey")
gold = Label(win, width=20, height=2, textvariable=g, state='normal', relief='sunk', bg="gold")
#pack into window
stand.grid(row=7, column=5, rowspan=2, columnspan=3, sticky=E, padx=50)
first.grid(row=9, column=4, rowspan=2, sticky=E, padx=2)
secon.grid(row=11, column=4, rowspan=2, sticky=E, padx=2)
third.grid(row=13, column=4, rowspan=2, sticky=E, padx=2)
#leading participants
bron.grid(row=9, column=5, rowspan=2, columnspan=3, sticky=E, padx=22)
silv.grid(row=11, column=5, rowspan=2, columnspan=3, sticky=E, padx=22)
gold.grid(row=13, column=5, rowspan=2, columnspan=3, sticky=E, padx=22)
win.mainloop()
...And the code for the "edit" window:
'''
Created on 29 Jan 2015
#author: James.D.Wood
'''
#!/usr/bin/env python
#init
from tkinter import *
global whichEvent, ea1, ea2, es1, es2, ed1, ed2, en1, en2
#create/define window
#edit window
Tk().withdraw()
editWin = Toplevel()
editWin.title("Edit participants")
editWin.minsize(350,400)
editWin.maxsize(350,400)
#define elements
whichEvent = StringVar()
whichEvent.set("[EVENT]") #testing
editLineImg = PhotoImage(file="resources/sline.gif", master=editWin)
#edit names boxes
ea1 = StringVar()
ea2 = StringVar()
es1 = StringVar()
es2 = StringVar()
ed1 = StringVar()
ed2 = StringVar()
en1 = StringVar()
en2 = StringVar()
editing = Label(editWin, text="Editing for:")
editEvent = Label(editWin, width=30, textvariable=whichEvent, state='normal', relief='sunk', bg='grey')
editLine = Label(editWin, image=editLineImg) #separator
editLine.image = editLineImg
blank2 = Label(editWin, text="")
blank3 = Label(editWin, text="")
blank4 = Label(editWin, text="")
blank5 = Label(editWin, text="")
#house labels
labAud = Label(editWin, text="Auden:")
labSut = Label(editWin, text="Sutherland:")
labDra = Label(editWin, text="Drake:")
labNew = Label(editWin, text="Newton:")
#edit names boxes
editAud1 = Entry(editWin, width=30, textvariable=ea1, justify=CENTER, state='normal', relief='sunk', bg='yellow')
editAud2 = Entry(editWin, width=30, textvariable=ea2, justify=CENTER, state='normal', relief='sunk', bg='yellow')
editSut1 = Entry(editWin, width=30, textvariable=es1, justify=CENTER, state='normal', relief='sunk', bg='blue')
editSut2 = Entry(editWin, width=30, textvariable=es2, justify=CENTER, state='normal', relief='sunk', bg='blue')
editDra1 = Entry(editWin, width=30, textvariable=ed1, justify=CENTER, state='normal', relief='sunk', bg='green')
editDra2 = Entry(editWin, width=30, textvariable=ed2, justify=CENTER, state='normal', relief='sunk', bg='green')
editNew1 = Entry(editWin, width=30, textvariable=en1, justify=CENTER, state='normal', relief='sunk', bg='red')
editNew2 = Entry(editWin, width=30, textvariable=en2, justify=CENTER, state='normal', relief='sunk', bg='red')
#pack into window
editing.grid(row=0, column=0, sticky=W, pady=15)
editEvent.grid(row=0, column=1, sticky=W, pady=10)
editLine.grid(row=1, column=0, columnspan=3, sticky=W)
#house labels
blank2.grid(row=2, column=1, sticky=W)
labAud.grid(row=3, column=0, rowspan=2, sticky=W, pady=10)
blank3.grid(row=5, column=1, sticky=W)
labSut.grid(row=6, column=0, rowspan=2, sticky=W, pady=10)
blank4.grid(row=8, column=1, sticky=W)
labDra.grid(row=9, column=0, rowspan=2, sticky=W, pady=10)
blank5.grid(row=11, column=1, sticky=W)
labNew.grid(row=12, column=0, rowspan=2, sticky=W, pady=10)
#edit names boxes
editAud1.grid(row=3, column=1, sticky=W)
editAud2.grid(row=4, column=1, sticky=W)
editSut1.grid(row=6, column=1, sticky=W)
editSut2.grid(row=7, column=1, sticky=W)
editDra1.grid(row=9, column=1, sticky=W)
editDra2.grid(row=10, column=1, sticky=W)
editNew1.grid(row=12, column=1, sticky=W)
editNew2.grid(row=13, column=1, sticky=W)
I'm at the point now where I'm wondering if it would actually just be better to write the whole program in a single .py file, though I thought that doing it this way would be more elegant.
If somebody could suggest a nice, streamlined solution for this that would keep the code for the two windows separate, I would be very grateful. I'm using Python 3.4, FYI.
Thanks.
When you import a module, you are executing its code. That how importing modules actually works in python. To stop it, put code in the imported module in a function or a class. To be fair, its still being run to make the functions or classes, but they wont be called automatically. They will be just defined. In the main file, you just call the functions/class from the imported module.
All top-level statements in a python module are run when the file is imported. In your case, because the entirety of your edit file is at the module-level, every statement gets run upon import. I'd suggest taking your 'edit' commands and putting then inside a function:
def run_edit_window():
... put your code here
Then in your main file, you will import the edit file first:
import edit # Assuming file is named 'edit.py'
Then, when your edit button is pressed, call:
edit.run_edit_window()