I made a game about guess numbers. After repeated attempts, I still couldn't change a problem. The code is as follows:
#
#
import tkinter
import random
import pygame
#
pygame.init()
#
root = tkinter.Tk()
#
bg = tkinter.Canvas(root, width=1000, height=750)
bg.pack()
bg_p = tkinter.PhotoImage(file="bg.png")
bg.create_image(500, 375, image=bg_p)
#
bgm = pygame.mixer.Sound("bgm.mp3")
bgm.play(-1)
#
low = 0
high = 101
#
random.randrange(low, high)
#
def onclick():
#
global low, high
#
guess = int(input("Guess a number: "))
#
if guess == answer:
#
bg = tkinter.Canvas(root, width=1000, height=750)
bg.pack()
bg_p = tkinter.PhotoImage(file="bingo.png")
bg.create_image(500, 375, image=bg_p)
#
low = guess
high = guess
#
bingo = pygame.mixer.Sound("bingo.mp3")
bingo.play(0)
#
elif guess > answer:
#
bg = tkinter.Canvas(root, width=1000, height=750)
bg.pack()
bg_p = tkinter.PhotoImage(file="too_high.png")
bg.create_image(500, 375, image=bg_p)
#
high = guess
#
lol = pygame.mixer.Sound("lol.mp3")
lol.play(0)
#
else:
#
bg = tkinter.Canvas(root, width=1000, height=750)
bg.pack()
bg_p = tkinter.PhotoImage(file="too_low.png")
bg.create_image(500, 375, image=bg_p)
#
low = guess
#
lol = pygame.mixer.Sound("lol.mp3")
lol.play(0)
#
while True:
#
for event in pygame.event.get():
#
if event.type == pygame.QUIT:
#
pygame.quit()
exit()
#
if event.type == pygame.MOUSEBUTTONDOWN:
#
onclick()
#
try:
#
l1.destroy()
l2.destroy()
#
except:
#
pass
#
finally:
#
l1 = tkinter.Label(root, text=str(low), font=("Arial", 60), bg="white")
l1.place(x=280, y=570)
l2 = tkinter.Label(root, text=str(high), font=("Arial", 60), bg="white")
l2.place(x=630, y=570)
#
root.mainloop()
After executing the program, _tkinter.TclError: can't invoke "label" command: application has been destroyed is returned. No matter where I put mainloop() it doesn't work. Why?
I put mainloop() on everywhere, but it still doesn't work.
You mix pygame
and tkinter
but it seems one big mess.
You try to use pygame.event
but you don't create pygame window
- so system will NOT send any events to pygame
. System sends pygame events
only to pygame window
- and this window has to be visible (active as top window on screen).
It will NOT generate pygame.MOUSEBUTTONDOWN
when you click in tkinter window
because it generates pygame event
only when you click inside pygame window
.
So it can't get pygame.QUIT
and pygame.MOUSEBUTTONDOWN
. And frankly, you don't need pygame loop if you use pygame
only to play sound.
If you create tkinter window
then you should use tkinter events
. And it means to use tkinter.Button(..., command=on_click)
to execute function when you click button. Or you have to use root.bind('<Button-1>', on_click)
to execute function when you click in any place in tkinter window
.
Here is my version - but I didn't test how works pygame.mixer
because at this moment I problem with audio on my Linux.
I create all widgets only once - and later I only replace text in Label
, and replace image on Canvas
I also uses tkinter.Entry
instead of input()
because it looks stupid when GUI uses terminal instead of widgets.
I don't use place()
but pack()
(or eventually grid()
) and I don't have to calculate manually positions. I also use tkinter.Frame
to put two labels in one row.
I add tkinter.Button
to check number but you can also press ENTER in tkinter.Entry
to check number.
import tkinter
import random
import pygame
# --- functions ---
def on_click(event=None): # default value for event because `command=` doesn't send event
global low, high
guess = int(entry.get()) # entry needs `.get()` to get value
if guess == answer:
bg.itemconfig(image_id, image=bg_p_bingo) # replace image in PhotoImage
low = guess
high = guess
label_low['text'] = str(low) # replace text in Label
label_high['text'] = str(high) # replace text in Label
#bingo = pygame.mixer.Sound("bingo.mp3")
#bingo.play(0)
elif guess > answer:
bg.itemconfig(image_id, image=bg_p_high) # replace image in PhotoImage
high = guess
label_high['text'] = str(high) # replace text in Label
#lol = pygame.mixer.Sound("lol.mp3")
#lol.play(0)
else:
bg.itemconfig(image_id, image=bg_p_low) # replace image in PhotoImage
low = guess
label_low['text'] = str(low) # replace text in Label
#lol = pygame.mixer.Sound("lol.mp3")
#lol.play(0)
# --- main ---
low = 0
high = 101
# ---
answer = random.randrange(low, high)
#pygame.mixer.init()
root = tkinter.Tk()
label = tkinter.Label(root, text="Guess a number: ")
label.pack(padx=5, pady=5)
entry = tkinter.Entry(root)
entry.pack(padx=5, pady=5)
button = tkinter.Button(root, text='CHECK', command=on_click)
button.pack(padx=5, pady=5)
entry.bind('<Return>', on_click) # run function on pressing ENTER - it sends `event` to function
bg = tkinter.Canvas(root, width=300, height=300)
bg.pack()
bg_p = tkinter.PhotoImage(file="bg.png")
bg_p_bingo = tkinter.PhotoImage(file="bingo.png")
bg_p_low = tkinter.PhotoImage(file="too_low.png")
bg_p_high = tkinter.PhotoImage(file="too_high.png")
image_id = bg.create_image(150, 150, image=bg_p, anchor='center')
frame = tkinter.Frame(root) # create Frame to put widgets in one row
frame.pack(fill='both', expand=True)
label_low = tkinter.Label(frame, text=f'{low}', font=("Arial", 30), bg="white", width=3)
label_low.pack(side='left', padx=5, pady=5, fill='x', expand=True)
label_high = tkinter.Label(frame, text=f'{high}', font=("Arial", 30), bg="white", width=3)
label_high.pack(side='right', padx=5, pady=5, fill='x', expand=True)
#bgm = pygame.mixer.Sound("bgm.mp3")
#bgm.play(-1)
root.mainloop()
pygame.mixer.quit()
I put code with images on GitHub furas/python-examples/tkinter/game-guess-number