Related
I have the Win.py file debugged and it worked well. However, according to #Matiiss, I will write the function like
def func():
lbl = ImageLabel(root)
lbl.pack()
lbl.load('D:/Personal/Game/Win.gif')
inside the main file, which is start2.py, but when I inserted the function inside the command, python outputs an error like NameError: name 'root' is not defined. I am not sure whether I need to change root into something else or not because I indeed didn't see root anywhere in either of the file. The following is the codes for the Win.py file.
import tkinter as tk
from PIL import Image, ImageTk
from itertools import count, cycle
class ImageLabel(tk.Label):
def load(self, im):
if isinstance(im, str):
im = Image.open(im)
frames = []
try:
for i in count(1):
frames.append(ImageTk.PhotoImage(im.copy()))
im.seek(i)
except EOFError:
pass
self.frames = cycle(frames)
try:
self.delay = im.info['duration']
except:
self.delay = 100
if len(frames) == 1:
self.config(image=next(self.frames))
else:
self.next_frame()
def unload(self):
self.config(image=None)
self.frames = None
def next_frame(self):
if self.frames:
self.config(image=next(self.frames))
self.after(self.delay, self.next_frame)
I don't know where is the root, but I don't know which argument to be added inside the lbl=ImageLabel().
The codes for start2.py, with correct indent.
import tkinter as tk
import pygame
from playsound import playsound
from Win import ImageLabel
display_width = 1000
display_height = 500
# Set up the display size
white = (255, 255, 255) # White
red = (255, 0, 0) # Red button background
picture = 'D:/Personal/Game UI.jpg' # The location of the picture
pygame.init() # Initialize class+
class Button(object): # Button class
def __init__(self, text, color, x=None, y=None, **kwargs):
self.surface = font.render(text, True, color)
self.WIDTH = self.surface.get_width()
self.HEIGHT = self.surface.get_height()
if 'centered_x' in kwargs and kwargs['centered_x']: # Show the place that a button will show up (x-axis)
self.x = display_width // 2 - self.WIDTH // 2
else:
self.x = x
if 'centered_y' in kwargs and kwargs['centered_y']: # Show the place that a button will show up (y-axis)
self.y = display_height // 2 - self.HEIGHT // 2
else:
self.y = y
def display(self):
screen.blit(self.surface, (self.x, self.y)) # Can't assign a value to a function
def check_click(self, position): # Track mouse behavior to show highlights
x_match = position[0] > self.x and position[0] < self.x + self.WIDTH
y_match = position[1] > self.y and position[1] < self.y + self.HEIGHT
if x_match and y_match:
return True
else:
return False
def start_screen(): # This function is used to load background and music
screen.blit(bg, (0, 0))
game_title = font.render("Start", True, white)
screen.blit(game_title, (display_width // 2 - game_title.get_width() // 2, 150))
play_button = Button("Play", red, None, 350, centered_x=True) # Start the game
exit_button = Button("Exit", white, None, 400, centered_x=True) # Exit the game
play_button.display()
exit_button.display()
pygame.display.update()
while True: # A conditional reading from while loop
if play_button.check_click(pygame.mouse.get_pos()):
play_button = Button('Play', red, None, 350, centered_x=True)
else:
play_button = Button('Play', white, None, 350, centered_x=True)
if exit_button.check_click(pygame.mouse.get_pos()):
exit_button = Button("Exit", red, None, 400, centered_x=True)
else:
exit_button = Button("Exit", red, None, 400, centered_x=True)
play_button.display()
exit_button.display()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit
if pygame.mouse.get_pressed()[0]:
if play_button.check_click(pygame.mouse.get_pos()):
break
if exit_button.check_click(pygame.mouse.get_pos()):
break
screen = pygame.display.set_mode((display_width, display_height)) # The use of the functions above
bg = pygame.image.load(picture)
font_addr = pygame.font.get_default_font()
font = pygame.font.Font(font_addr, 36)
start_screen()
LARGE_FONT = ("Verdana", 12) # Font
# TODO: sound is defined here
def fail1():
playsound("D:/Personal/Game/wha-wha.mp3", block=False)
def fail2():
playsound("D:/Personal/Game/Nope-Sound-Effect.wav", block=False) # TODO: bug here, use wav format
def fail3():
playsound("D:/Personal/Game/friday-damn.mp3", block=False)
def fail4():
playsound("D:/Personal/Game/export_4.mp3", block=False)
def fail5():
playsound("D:/Personal/Game/Aww.mp3", block=False)
def fail6():
playsound("D:/Personal/Game/Laughing.mp3", block=False)
def fail7():
playsound("D:/Personal/Game/Incorrect.mp3", block=False)
def give_up():
playsound("D:/Personal/Game/Fail.mp3", block=False)
def try_again():
playsound("D:/Personal/Game/Here-we-go.mp3", block=False)
def success1():
playsound("D:/Personal/Game/Yah.mp3", block=False)
def gif():
top = tk.Toplevel(app)
lbl = ImageLabel(top)
lbl.pack()
lbl.load('D:/Personal/Game/Win.gif')
class SeaofBTCapp(tk.Tk): # Define a class for the tk windows
def __init__(self, *args, **kwargs): # Base properties of tk windows
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
'''https://stackoverflow.com/questions/64470478/keyerror-class-main-page2-in-python-tkinter For range means
that the buttons will be loaded for multiple times, whenever a new option is added, for range needs to be
defined. '''
for F in (
StartPage, MCQ, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Failure, Success,
Credits): # TODO: add the class number into the for loop here
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame): # Start page
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="This will test your chemistry ability. Ready to start?", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button = tk.Button(self, text="Enter",
command=lambda: [controller.show_frame(MCQ), try_again()]) # This will show the next window
button.pack()
button2 = tk.Button(self, text="Cancel",
command=lambda: controller.destroy()) # This will close the window
button2.pack()
class MCQ(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! Question 1: What is proton number equal to?", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Atomic mass",
command=lambda: [self.correspondingBehavior("Sorry, you died. Better luck next time!"),
controller.show_frame(Failure), fail1()])
button1.pack()
button2 = tk.Button(self, text="Number of moles",
command=lambda: [self.correspondingBehavior("Sorry, you died. Better luck next time!"),
controller.show_frame(Failure), fail1()])
button2.pack()
button3 = tk.Button(self, text="Atomic number",
command=lambda: controller.show_frame(Q2))
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! Question 2: Which of the two statements describes the word "
"endothermic?", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Give out heat", command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah..."),
controller.show_frame(Failure), fail2()])
button1.pack()
button2 = tk.Button(self, text="Take in heat", command=lambda: controller.show_frame(Q3))
button2.pack()
button3 = tk.Button(self, text="Give up",
command=lambda: self.correspondingBehavior("Don't give up!"))
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q3(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! Question :3 he symbol Ag stands for which element?", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Gold",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... EPIC FAIL!!! Gold is Au!"),
controller.show_frame(Failure), fail2()])
button1.pack()
button2 = tk.Button(self, text="Silver", command=lambda: controller.show_frame(Q4))
button2.pack()
button3 = tk.Button(self, text="Hydrogen",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... EPIC FAIL!!! Hydrogen is H!"),
controller.show_frame(Failure), fail2()])
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q4(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! Question 3: Organic chemistry is the study of the compounds that "
"make up living organisms. All organic molecules contain:", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Carbon only",
command=lambda: [self.correspondingBehavior("WHH! Check your book.."),
controller.show_frame(Failure), fail3()])
button1.pack()
button2 = tk.Button(self, text="Carbon and nitrogen",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... You died!"),
controller.show_frame(Failure), fail3()])
button2.pack()
button3 = tk.Button(self, text="Carbon and hydrogen",
command=lambda: controller.show_frame(Q5))
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q5(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!!A molecule with the formula C3H8 is a(n)", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="hexane",
command=lambda: [self.correspondingBehavior("Nope, it's C6H14"),
controller.show_frame(Failure), fail4()])
button1.pack()
button2 = tk.Button(self, text="propane", command=lambda: controller.show_frame(Q6))
button2.pack()
button3 = tk.Button(self, text="butane",
command=lambda: [self.correspondingBehavior("Nope, it's C4H10"),
controller.show_frame(Failure), fail4()])
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q6(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!!A substance that speeds up the rate of a chemical reaction without "
"undergoing any change itself "
"is known as a _______", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="catalyst",
command=lambda: controller.show_frame(Q7))
button1.pack()
button2 = tk.Button(self, text="cation", command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... What a "
"pity! But cation is a "
"positive charge."),
controller.show_frame(Failure), fail4()])
button2.pack()
button3 = tk.Button(self, text="counter ion",
command=lambda: [self.correspondingBehavior("Nope, it's the ion that accompanies an ionic "
"species in order to maintain electric "
"neutrality."), controller.show_frame(Failure),
fail4()])
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q7(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! All of the following are amino acids except:",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Tryptophan",
command=lambda: [self.correspondingBehavior("Nope, adenine is a nucleic acid, not an "
"amino acid."), controller.show_frame(Failure),
fail6()])
button1.pack()
button2 = tk.Button(self, text="Tyrosine",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... Adenine is a nucleic acid, "
"not an amino acid."),
controller.show_frame(Failure), fail6()])
button2.pack()
button3 = tk.Button(self, text="Adenine",
command=lambda: controller.show_frame(Q8))
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q8(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!!A mole contains Avogadro's number of items. What is Avogadro's number?",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="6023",
command=lambda: [self.correspondingBehavior("Wrong...Check your chemistry book"),
controller.show_frame(Failure), fail5()])
button1.pack()
button2 = tk.Button(self, text="C. 6.02 x 10^-23",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... What a "
"pity! But the value is larger than that..."),
controller.show_frame(Failure), fail5()])
button2.pack()
button3 = tk.Button(self, text="6.023 x 10^23",
command=lambda: controller.show_frame(Q9))
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q9(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!!The person given credit for developing the first modern periodic "
"table is",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Democritus",
command=lambda: [self.correspondingBehavior("Wrong...He was famous for the formulation of "
"an atomic theory of the universe"),
controller.show_frame(Failure), fail7()])
button1.pack()
button2 = tk.Button(self, text="Mendeleev",
command=lambda: controller.show_frame(Q10))
button2.pack()
button3 = tk.Button(self, text="Thomson",
command=lambda: [self.correspondingBehavior("Wah-ah-ah-ah... What a "
"pity! He is the one who did a detailed study "
"of cathode rays and proved the existence of "
"the electron in atoms"),
controller.show_frame(Failure), fail7()])
button3.pack()
button4 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button4.pack()
def correspondingBehavior(self, choice):
print(choice)
class Q10(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="MCQ test!!! Does group or period in the periodic table represent outer shell "
"electrons?",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Period",
command=lambda: [self.correspondingBehavior("Wrong...You can draw it out and see"),
controller.show_frame(Failure), fail7()])
button1.pack()
button2 = tk.Button(self, text="Group",
command=lambda: (controller.show_frame(Success))) # TODO: find a way
button2.pack()
button3 = tk.Button(self, text="Quit", command=lambda: [controller.show_frame(Credits), give_up()])
button3.pack()
def correspondingBehavior(self, choice):
print(choice)
class Success(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Yay! You have passed my chemistry challenge! Would you like to continue?",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Continue", command=[gif(), success1()])
button1.pack()
button2 = tk.Button(self, text="Quit", command=lambda: controller.destroy())
button2.pack()
def correspondingBehavior(self, choice): # Comment
print(choice)
class Failure(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Sorry about that, but you failed. Would you like to try again?",
font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Yes", command=lambda: [controller.show_frame(MCQ), try_again()])
button1.pack()
button2 = tk.Button(self, text="No", command=lambda: controller.show_frame(Credits))
button2.pack()
def correspondingBehavior(self, choice):
print(choice)
app = SeaofBTCapp()
app.mainloop()
'''
Now the codes are in a mess and I am going to write the comments after debugging.
Since there is no information on start2.py, below is an example that you may put in start2.py based on your posted codes:
import tkinter as tk
from Win import ImageLabel
def func():
lbl = ImageLabel(root)
lbl.pack()
lbl.load("D:/Personal/Game/Win.gif")
root = tk.Tk() # the root window for the ImageLabel
func()
root.mainloop()
I am new to object oriented python programming. Currently I am using Python 3. I want to create an app which has multiple pages. I am able to navigate between pages but find it difficult to add image in the background.
Please note I don't want to know how to background image in tkinter as I am already able to do it based on the following code.
bg = PhotoImage(file="images\\bg.png")
label_bgImage = Label(master, image=bg)
label_bgImage.place(x=0, y=0)
I want to know how to add background image to pages when you are defining each window as a class. I put the code to insert background image in the __init__() method of class ABCApp. When I tried to insert the code for adding background image to my existing code, it stopped showing the labels and buttons and now just shows the window.
The following code was my attempt to add an image as background.
import tkinter as tk
from tkinter import ttk
from tkinter import *
class ABCApp(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,*args,**kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self)
main_frame.pack(side = 'top',fill = 'both',expand ='True')
main_frame.grid_rowconfigure(0,weight=1)
main_frame.grid_columnconfigure(0,weight=1)
bg = PhotoImage(file="images\\bg.png")
label_bgImage = Label(self, image=bg)
label_bgImage.place(x=0, y=0)
self.frames = {}
for F in (HomePage,PageOne,PageTwo):
frame = F(main_frame, self)
self.frames[F] = frame
frame.grid(row=0,column=0,sticky='nsew')
self.show_frame(HomePage)
def show_frame(self,container):
frame = self.frames[container]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self,text='Home Page',font =("Helvetica",20))
label.pack(padx=10,pady=10)
button1 = ttk.Button(self,text = "Page 1",command = lambda: controller.show_frame(PageOne))
button1.pack()
button6 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
button6.pack()
class PageOne(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
button2 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
button2.pack()
button5 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
button5.pack()
class PageTwo(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
label2.pack(padx=10, pady=10)
button3 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
button3.pack()
button4 = ttk.Button(self, text="Page 1", command=lambda: controller.show_frame(PageOne))
button4.pack()
app = ABCApp()
app.mainloop()
I would like to have the same or different image to appear as background of each page. Either way I am satisfied.
Since the background image is the same on all the Page classes, an object-oriented way to do it would be to define a base class with the background image on it and then derive all of the concrete Page classes from that instead of a plain tk.Frame. Afterwards, each subclass will need to call its base class' __init__() method before adding whatever widgets are unique to it. In the code below, this new base class is the one named BasePage.
To avoid loading a separate copy of the image file for each BasePage subclass instance, it's only done once and saved as an attribute of the ABCApp class (which is the controller argument being passed to the constructor of each BasePage subclass). Because each page class completely covers-up all the others when it's made visible, each one does need to create its own Label with the background image on it.
Below shows what I mean. (Note I've made the code more PEP 8 - Style Guide for Python Code compliant than what's in your question).
import tkinter as tk
from tkinter.constants import *
from tkinter import ttk
class ABCApp(tk.Tk):
BKGR_IMAGE_PATH = '8-ball.png'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self)
main_frame.pack(side='top', fill='both', expand='True')
main_frame.grid_rowconfigure(0, weight=1)
main_frame.grid_columnconfigure(0, weight=1)
self.bkgr_image = tk.PhotoImage(file=self.BKGR_IMAGE_PATH)
self.frames = {}
for F in (HomePage, PageOne, PageTwo):
frame = F(main_frame, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(HomePage)
def show_frame(self,container):
frame = self.frames[container]
frame.tkraise()
class BasePage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
label_bkgr = tk.Label(self, image=controller.bkgr_image)
label_bkgr.place(relx=0.5, rely=0.5, anchor=CENTER) # Center label w/image.
class HomePage(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = ttk.Label(self, text='Home Page', font =("Helvetica",20))
label.pack(padx=10, pady=10)
button1 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button6 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button6.pack()
class PageOne(BasePage):
def __init__(self,parent,controller):
super().__init__(parent, controller)
label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
button2 = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(HomePage))
button2.pack()
button5 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button5.pack()
class PageTwo(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
label2.pack(padx=10, pady=10)
button3 = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(HomePage))
button3.pack()
button4 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button4.pack()
app = ABCApp()
app.mainloop()
Also note that if you wanted each Page class to have a different background image, you would do things a little differently — i.e. each page would become responsible for loading its own image. To do that, the call to the BasePage constructor would need to be passed the name of the image file to be used (as an additional argument in the super().__init__() statement).
Okay, so I am been learning python for 2 weeks and implementing TkInter now, I am trying to make an project where the user can set an Alarm and when the alarm rings the user will hit stop then the program will ask the user some random math questions, I been messing around and got everything up to the Math problem to work, I have a lot of placeholders in place and I am stuck with getting the answer of x and y to return to an INT, I have it made where it will show what x+y will equal and what the user enter but when I run the while loop my program just freezes. I assume its because the answer returns as a Label and that's not an INT, so all my issues are in my Math Class and have been trying for 3 days and cant figure it out. Please anything will be helpful, I tried using the .get method but that also gives me errors.
import tkinter as tk
import time
import datetime
from tkinter import *
from winsound import PlaySound, SND_FILENAME, SND_LOOP, SND_ASYNC
import random
class WakeUpApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side='top', fill='both', expand='true',)
container.grid_rowconfigure(0, minsize=400, weight=1)
container.grid_columnconfigure(0, minsize=250, weight=2)
self.frames = {}
for F in (Alarm, Chooser, Difficulty, Math):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(Alarm)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
present = datetime.datetime.now()
now = present.strftime("%H:%M:%S")
class Alarm(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Alarm.hour = tk.StringVar()
Alarm.min = tk.StringVar()
Alarm.sec = tk.StringVar()
hour_a = tk.Entry(self, text=Alarm.hour, width=4).place(x=50, y=50)
min_a = tk.Entry(self, text=Alarm.min, width=4).place(x=70, y=50)
sec_a = tk.Entry(self, text=Alarm.sec, width=4).place(x=90, y=50)
current_time = tk.Label(self, text=f'Current Time: {now}').place(x=0, y=30)
set_time = tk.Label(self, text='Set Time').place(x=0, y=50)
'''
VERY IMPORTANT -- THIS CODE STARTS THE ALARM
setalarm = tk.Button(self, text='Set Alarm', command=lambda: wake())
setalarm.place(x=90, y=90)
'''
setalarm = tk.Button(self, text='Set Alarm', command=lambda: controller.show_frame(Chooser))
setalarm.place(x=90, y=90)
def wake():
alarm_time = f'{Alarm.hour.get()}:{Alarm.min.get()}:{Alarm.sec.get()}'
alarm_clock(alarm_time)
def play_sound(self,):
PlaySound('Sound.wav', SND_FILENAME|SND_LOOP|SND_ASYNC)
def stop_sound(self):
PlaySound(None, SND_FILENAME)
def alarm_clock(alarm_time):
while True:
time.sleep(1)
present = datetime.datetime.now()
now = present.strftime("%H:%M:%S")
print(now)
if now == alarm_time:
break
if now == alarm_time:
play_sound(self)
testbutton = Button(self, text='pls work', command=lambda: stop_sound(self))
testbutton.pack()
class Chooser(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Please Choose Your Wake Up Game')
label.pack(pady=50, padx=50)
math = tk.Button(self, text='Math Game',
height=5, width=15,
command=lambda: controller.show_frame(Difficulty))
math.place(x=125, y=75)
guesser = tk.Button(self, text='Guessing Game',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
guesser.place(x=125, y=175)
class Difficulty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Please Choose Your Difficulty for the Questions')
label.pack(pady=50, padx=50)
level1 = tk.Button(self, text='Level 1 \n ie: 12+17',
height=5, width=15,
command=lambda: controller.show_frame(Math))
level1.place(x=125, y=75)
level2 = tk.Button(self, text='Level 2 \n ie: 12*9',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
level2.place(x=125, y=175)
level3 = tk.Button(self, text='Level 3 \n ie: 6*7+21',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
level3.place(x=125, y=275)
class Math(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
x = tk.IntVar()
y = tk.IntVar()
z = tk.IntVar()
ab = tk.IntVar()
x = random.randint(1, 10)
y = random.randint(1, 10)
xy = int(x + y)
problem = tk.Label(self, text=f'{x} + {y}').place(x=0, y=30)
goal = tk.Label(self, text=xy).place(x=0, y=90)
solution = tk.Entry(self, text=z).place(x=0, y=50)
new = tk.Entry(self, text=ab).place(x=0, y=70)
def answer2(self):
py_guess = tk.Label(self, text=ab.get()).place(x=125, y=120)
button2 = tk.Button(self, text='GIVE ME Z PLS', command=lambda: answer())
button2.pack()
button2 = tk.Button(self, text='The Problem', command=lambda: answer2(self))
button2.pack()
def answer():
user_guess = tk.Label(self, text=z.get()).place(x=125, y=100)
level1(user_guess)
def level1(user_guess):
keepGoing = True
while keepGoing:
if (z == xy):
good = tk.Label(self, text='good job').pack()
keepGoing = False
else:
bad = tk.Label(self, text='nope go again').pack()
string_solution = solution.get()
int_solution = int(string_solution)
app = WakeUpApp()
app.mainloop()
I'm trying to ask the user to input a number (in this example, they need to enter a number of minutes into the minEntry box). I want to take this number and use it to set multiple variable values by multiplying this value with other numbers. Then i want to take this value and have it displayed in the sublabel box within the __init__ function. Im getting an error message that says 'PageSix' object has no attribute 'peak_rate'. I sort of know what this means but i have no idea how to solve it.
class PageSix(tk.Frame):
def projected_figures(self):
global minEntry
tariff = self.controller.page_get(PageTwo)
minutes=minEntry.get()
self.peak_rate = tk.StringVar()
self.peak_rate.set(0)
self.off_peak = tk.StringVar()
self.off_peak.set(0)
self.line_rental = tk.StringVar()
self.line_rental.set(0)
if tariff.current_tariff == "A":
self.peak_rate.set("Peak Rate: £"+minutes*0.3)
self.off_peak.set("Off-Peak: £"+minutes*0.05)
self.line_rental.set("Line Rental: £15")
elif tariff.current_tariff == "B":
self.peak_rate.set("Peak Rate: £"+minutes*0.1)
self.off_peak.set("Off-Peak: £"+minutes*0.02)
self.line_rental.set("Line Rental: £20")
else:
self.peak_rate.set("Peak Rate: £"+minutes*0.9)
self.off_peak.set("Off-Peak: -")
self.line_rental.set("Line Rental: £30")
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
label = tk.Label(self, text="Account Balance", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, textvariable=self.peak_rate, font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
sublabel2 = tk.Label(self, textvariable=self.off_peak, font=SMALL_FONT)
sublabel2.pack(pady=10,padx=10)
sublabel3 = tk.Label(self, textvariable=self.line_rental, font=SMALL_FONT)
sublabel3.pack(pady=10,padx=10)
minLabel = Label(self, text = 'Enter Minutes: ')
minEntry = Entry(self)
minLabel.pack(pady =10, padx = 10, side = TOP, anchor = S)
minEntry.pack(pady =10, padx = 10, side = TOP, anchor = S)
button1 = tk.Button(self, text="View Projected Figures",
command=self.projected_figures)
button1.pack()
button2 = tk.Button(self, text="Back to Menu",
command=lambda: controller.show_frame(StartPage))
button2.pack()
Also the lines tariff = self.controller.get_page(PageTwo) and if self.current_tariff == "x" are referring to this class if it can be of any use.
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
self.current_tariff = tk.StringVar()
self.current_tariff.set("A")
label = tk.Label(self, text="Current Tariff", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, textvariable=self.current_tariff, font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Change Tariff",
command=lambda: controller.show_frame(PageSix))
button1.pack()
button2 = tk.Button(self, text="Projected Figures",
command=lambda: controller.show_frame(PageSix))
button2.pack()
button3 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button3.pack()
__init__ gets called as soon as you initialize the class and projected_figures will be called when you call it.
When you try to initialize PageSix, inside of __init__ at sublabel creation line, there is no variable named self.peak_rate since projected_figures hasn't called yet.
Moving variable creations inside of __init__ should solve this issue.
def __init__(self, parent, controller):
...
self.peak_rate = tk.StringVar()
self.peak_rate.set(0)
self.off_peak = tk.StringVar()
self.off_peak.set(0)
self.line_rental = tk.StringVar()
self.line_rental.set(0)
...
I am using a container class in TKinter to start with a Menu screen and be able to switch to one of two other screens when necessary. It isn't quite working correctly and I'm not sure why.
Here is what my main menu screen looks like:
http://i62.tinypic.com/2nhoju0.jpg (won't let me post images yet)
When I click New Game, it looks like this:
http://i57.tinypic.com/x3tglg.jpg (won't let me post images yet)
Clearly, the new game and continue buttons are not supposed to be there, and there should only be one quit button. There should also be a label at the top kinda like the main menu screen.
Can anyone tell me why this is happening?
Here is the relevant code:
class Battleship():
def __init__(self, root):
self.root = root
self.pages = {}
container = Frame(root)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
for P in (MainMenu, ShipSelect, BattleScreen):
frame = P(container, self)
frame.grid(row=0, column=0, sticky="nsew")
self.pages[P] = frame
self.show_frame(MainMenu)
def show_frame(self, cont):
frame = self.pages[cont]
frame.tkraise()
class MainMenu(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Welcome to PyBattleship!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(root, text='New Game', width=13, command=lambda :controller.show_frame(ShipSelect))
button1.pack()
button2 = Button(root, text='Continue Game', width=13)
button2.pack()
button3 = Button(root, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button3.pack()
class ShipSelect(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.root = root
label = Label(self, text="Please place your ships", font=LARGE_FONT)
button1 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button1.pack()
root = Tk()
root.title('Py-Battleship')
sheet = Battleship(root)
root.mainloop()
I just realized that I was still using 'root' for the button widgets in MainMenu. When I changed the 'roots' to 'self' and added padding to the label in ShipSelect, it seems to work.
class MainMenu(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Welcome to PyBattleship!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(self, text='New Game', width=13, command=lambda controller=controller:controller.show_frame(ShipSelect))
button1.pack()
button2 = Button(self, text='Continue Game', width=13)
button2.pack()
button3 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button3.pack()
class ShipSelect(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Please place your ships", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button1.pack()
Using a mixture of grid and pack in tkinter is never a good idea, which is one of the reasons your code might be having unpredictable results. Secondly, you are trying to pack the buttons to the root window, rather than one of the frames you have created.