Python Returns An Error When I Try To Quit The Application Window
Solution 1:
It looks like turtle uses tkinter. In Tk there's a method named protocol which you can use to control what happens when certain events happen, one of those being hitting the red 'X'.
In order to invoke that we need to get the root level window.
Placing
canvas = wn.getcanvas()
root = canvas.winfo_toplevel()
will set root as your root window.
From here you can use root.protocol("WM_DELETE_WINDOW", on_close)
to invoke a function named on_close
or whatever you want to name it.
Your function will probably look something like this.
def on_close():
global running
running = False
This will break you out of your loop and close your program.
Full Code.
import turtle
wn = turtle.Screen()
canvas = wn.getcanvas()
root = canvas.winfo_toplevel()
wn.title("Pong")
wn.bgcolor('black')
wn.setup(width=800, height=600)
wn.tracer(0)
#Score
score_a = 0
score_b = 0
#paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=5, stretch_len = 1)
paddle_a.penup()
paddle_a.goto(-350,0)
#paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("white")
paddle_b.shapesize(stretch_wid=5, stretch_len = 1)
paddle_b.penup()
paddle_b.goto(350,0)
#Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.penup()
ball.goto(0,0)
ball.dx = 0.5
ball.dy = 0.5
#pen
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0,260)
pen.write("Player A: 0 Player B: 0", align="center", font=('Courier', 24, "normal"))
#Function
def paddle_a_up():
y = paddle_a.ycor()
y+=20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y-=20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y+=20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y-=20
paddle_b.sety(y)
#Keyboard binding
wn.listen()
wn.onkeypress(paddle_a_up, "w")
wn.onkeypress(paddle_a_down, "s")
wn.onkeypress(paddle_b_up, "Up")
wn.onkeypress(paddle_b_down, "Down")
def on_close():
global running
running = False
root.protocol("WM_DELETE_WINDOW", on_close)
running = True
#main game loop
while running:
wn.update()
#move the ball
ball.setx(ball.xcor()+ball.dx)
ball.sety(ball.ycor()+ball.dy)
#border
if ball.ycor() > 280:
ball.sety(280)
ball.dy*=-1
if ball.ycor() < -280:
ball.sety(-280)
ball.dy*=-1
if ball.xcor() > 380:
ball.goto(0,0)
ball.dx*=-1
score_a+=1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
if ball.xcor() < -380:
ball.goto(0,0)
ball.dx*=-1
score_b += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
#colliosion
if (ball.xcor() > 330 and ball.xcor() < 340) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() -50):
ball.setx(330)
ball.dx*=-1
if (ball.xcor() < -330 and ball.xcor() > -340) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() -50):
ball.setx(-330)
ball.dx*=-1
Solution 2:
We can solve this problem from within turtle, no need to drop down to tkinter underpinnings. Generally, you need to play by the rules. Specifically, no while running:
aka while True:
. Turtle is an event-based environment and you're not letting events get handled properly and thus the error messages.
Instead of the while
loop, we need an ontimer()
event:
from turtle import Screen, Turtle
FONT = ('Courier', 24, 'normal')
# Score
score_a = 0
score_b = 0
# Function
def paddle_a_up():
paddle_a.sety(paddle_a.ycor() + 20)
def paddle_a_down():
paddle_a.sety(paddle_a.ycor() - 20)
def paddle_b_up():
paddle_b.sety(paddle_b.ycor() + 20)
def paddle_b_down():
paddle_b.sety(paddle_b.ycor() - 20)
def single_step():
global score_a, score_b
# move the ball
ball.setposition(ball.xcor() + ball.dx, ball.ycor() + ball.dy)
# border
if ball.ycor() > 280:
ball.sety(280)
ball.dy *= -1
elif ball.ycor() < -280:
ball.sety(-280)
ball.dy *= -1
if ball.xcor() > 380:
ball.goto(0, 0)
ball.dx *= -1
score_a += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align='center', font=FONT)
if ball.xcor() < -380:
ball.goto(0, 0)
ball.dx *= -1
score_b += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align='center', font=FONT)
# collision
if 330 < ball.xcor() < 340 and paddle_b.ycor() - 50 < ball.ycor() < paddle_b.ycor() + 50:
ball.setx(330)
ball.dx *= -1
elif -340 < ball.xcor() < -330 and paddle_a.ycor() - 50 < ball.ycor() < paddle_a.ycor() + 50:
ball.setx(-330)
ball.dx *= -1
screen.update()
screen.ontimer(single_step)
screen = Screen()
screen.title('Pong')
screen.bgcolor('black')
screen.setup(width=800, height=600)
screen.tracer(0)
# paddle A
paddle_a = Turtle()
paddle_a.shape('square')
paddle_a.color('white')
paddle_a.shapesize(stretch_wid=5, stretch_len=1)
paddle_a.penup()
paddle_a.setx(-350)
# paddle B
paddle_b = Turtle()
paddle_b.shape('square')
paddle_b.color('white')
paddle_b.shapesize(stretch_wid=5, stretch_len=1)
paddle_b.penup()
paddle_b.setx(350)
# Ball
ball = Turtle()
ball.shape('circle')
ball.color('white')
ball.penup()
ball.dx = 1
ball.dy = 1
# pen
pen = Turtle()
pen.hideturtle()
pen.color('white')
pen.penup()
pen.sety(260)
pen.write("Player A: 0 Player B: 0", align='center', font=FONT)
# Keyboard binding
screen.onkeypress(paddle_a_up, 'w')
screen.onkeypress(paddle_a_down, 's')
screen.onkeypress(paddle_b_up, 'Up')
screen.onkeypress(paddle_b_down, 'Down')
screen.listen()
single_step()
screen.mainloop()
Now when you close the window, that event will be handled by the same mainloop
event handler that's running your game.
Post a Comment for "Python Returns An Error When I Try To Quit The Application Window"