这行代码会导致程序无法响应重新启动功能。

3
我尝试用Python编写一个程序,让用户在龟赛中押注,并在比赛结束后告诉他是否猜对了。我希望用户能通过点击“r”来选择重新开始比赛(我使用了turtle.onkey方法),这一点也很顺利,直到我加入了下面这行代码:
bet = screen.textinput("Choose your bet", "Enter blue or green:")
现在程序允许用户像我想要的那样选择自己的押注,但是之后它就不会再响应任何.onkey方法了。有人知道为什么会发生这种情况吗?
import turtle
import random
import ctypes

speed = random.randint(0, 2)

myTurtle = turtle.Turtle()
myTurtle2 = turtle.Turtle()
screen = turtle.Screen()
def up():
    myTurtle.setheading(90)
    myTurtle.forward(10)

def down():
    myTurtle.setheading(270)
    myTurtle.forward(10)

def left():
    myTurtle.setheading(180)
    myTurtle.forward(10)

def right():
    myTurtle.setheading(0)
    myTurtle.forward(10)

def up2():
    myTurtle2.setheading(90)
    myTurtle2.forward(10)

def down2():
    myTurtle2.setheading(270)
    myTurtle2.forward(10)

def left2():
    myTurtle2.setheading(180)
    myTurtle2.forward(10)

def right2():
    myTurtle2.setheading(0)
    myTurtle2.forward(10)

def restart():
    myTurtle.setposition(400, -300)
    myTurtle.setheading(90)
    myTurtle2.setposition(-400, -300)
    myTurtle2.setheading(90)
    speed = random.randint(0, 2)
    bet = screen.textinput("Choose your bet", "Enter blue or green: ")
    while myTurtle.ycor() < 300 and myTurtle2.ycor() < 300:
        if speed == 1:
            up()
        elif speed == 2:
            up2()
        speed = random.randint(0, 2)
    if myTurtle.ycor() == 300:
        if bet == "blue":
            ctypes.windll.user32.MessageBoxW(0, "Blue is the winner", "You win!", 0x00010000)
        else:
            ctypes.windll.user32.MessageBoxW(0, "Blue is the winner", "You lost", 0x00010000)
    else:
        if bet == "green":
            ctypes.windll.user32.MessageBoxW(0, "Green is the winner", "You win!", 0x00010000)
        else:
            ctypes.windll.user32.MessageBoxW(0, "Green is the winner", "You lost", 0x00010000)

screen.title("Turtle race")
turtle.listen()
myTurtle.shape("turtle")
myTurtle2.shape("turtle")
myTurtle.setposition(400,-300)
myTurtle.setheading(90)
myTurtle2.setposition(-400,-300)
myTurtle2.setheading(90)
myTurtle.dot(10, "blue")
myTurtle2.dot(10, "green")
myTurtle.pencolor("blue")
myTurtle2.pencolor("green")

myTurtle.speed(0)
myTurtle2.speed(0)
bet = screen.textinput("Choose your bet", "Enter blue or green: ")
while myTurtle.ycor() < 300 and myTurtle2.ycor() < 300:
    if speed == 1:
        up()
    elif speed == 2:
        up2()
    speed = random.randint(0, 2)

if myTurtle.ycor() == 300:
    if bet == "blue":
        ctypes.windll.user32.MessageBoxW(0, "Blue is the winner", "You win!", 0x00010000)
    else:
        ctypes.windll.user32.MessageBoxW(0, "Blue is the winner", "You lost", 0x00010000)
else:
    if bet == "green":
        ctypes.windll.user32.MessageBoxW(0, "Green is the winner", "You win!", 0x00010000)
    else:
        ctypes.windll.user32.MessageBoxW(0, "Green is the winner", "You lost", 0x00010000)



turtle.onkey(up, 'Up')
turtle.onkey(down, 'Down')
turtle.onkey(left, 'Left')
turtle.onkey(right, 'Right')

turtle.onkey(restart, 'r')

turtle.onkey(up2, 'w')
turtle.onkey(down2, 's')
turtle.onkey(left2, 'a')
turtle.onkey(right2, 'd')
turtle.mainloop()

就我而言,“textinput”必须对所有键做出反应,以便可以删除所有“onkey”。您尝试在“textinput”之后重新分配“onkey”了吗? - furas
可能还有另一个问题 - while 循环一直运行并阻塞了 mainloop(),而 mainloop() 负责获取系统的键盘/鼠标事件并检查是否点击了 r 并执行相应的函数。这时候需要使用 ontimer 代替 while 来定期重复执行函数,以避免阻塞 mainloop() - furas
请查看文档中的key,在onkey()之后需要添加listen()才能访问系统中的按键。 - furas
1个回答

1
问题在于onkey需要主窗口聚焦才能从系统获取按键,但是当你执行textinput时,焦点就会丢失,需要再次执行screen.listen()

最小工作代码。

由于您在restart()内外重复一些代码,所以我运行restart()而不是外部代码。

因为我不使用Windows,所以我使用tkinter.messagebox来显示消息。 turtle已经使用tkinter来显示带有画布和textinput的主窗口。

import turtle
import random
#import tkinter  as tk
from tkinter import messagebox

# functions ---

def up():
    myTurtle.setheading(90)
    myTurtle.forward(10)

def down():
    myTurtle.setheading(270)
    myTurtle.forward(10)

def left():
    myTurtle.setheading(180)
    myTurtle.forward(10)

def right():
    myTurtle.setheading(0)
    myTurtle.forward(10)

def up2():
    myTurtle2.setheading(90)
    myTurtle2.forward(10)

def down2():
    myTurtle2.setheading(270)
    myTurtle2.forward(10)

def left2():
    myTurtle2.setheading(180)
    myTurtle2.forward(10)

def right2():
    myTurtle2.setheading(0)
    myTurtle2.forward(10)

def restart():
    myTurtle.setposition(400, -300)
    myTurtle.setheading(90)
    myTurtle2.setposition(-400, -300)
    myTurtle2.setheading(90)
    
    speed = random.randint(0, 2)
    bet = screen.textinput("Choose your bet", "Enter blue or green: ")

    screen.listen()  # <--- set focus on main window after `textinput`
    
    while myTurtle.ycor() < 300 and myTurtle2.ycor() < 300:
        if speed == 1:
            up()
        elif speed == 2:
            up2()
        speed = random.randint(0, 2)

    if myTurtle.ycor() == 300:
        if bet == "blue":
            messagebox.showinfo("Result", "Blue is the winner\n\nYou win!")
        else:
            messagebox.showinfo("Result", "Blue is the winner\n\nYou lost")
    else:
        if bet == "green":
            messagebox.showinfo("Result", "Green is the winner\n\nYou win!")
        else:
            messagebox.showinfo("Result", "Green is the winner\n\nYou lost")
    
# --- main ---

speed = random.randint(0, 2)

myTurtle  = turtle.Turtle()
myTurtle2 = turtle.Turtle()

screen = turtle.Screen()
screen.title("Turtle race")

myTurtle.shape("turtle")
myTurtle2.shape("turtle")

turtle.onkey(up, 'Up')
turtle.onkey(down, 'Down')
turtle.onkey(left, 'Left')
turtle.onkey(right, 'Right')

turtle.onkey(restart, 'r')

turtle.onkey(up2, 'w')
turtle.onkey(down2, 's')
turtle.onkey(left2, 'a')
turtle.onkey(right2, 'd')

restart()

turtle.mainloop()

编辑:

精简代码 - 我把乌龟放在列表中,稍后我可以使用myTurtles[number],并且我可以使用一个函数up(number)代替两个函数up()up2()

import turtle
import random
from tkinter import messagebox

# functions ---

def up(number):
    myTurtles[number].setheading(90)
    myTurtles[number].forward(10)

def down(number):
    myTurtles[number].setheading(270)
    myTurtles[number].forward(10)

def left(number):
    myTurtles[number].setheading(180)
    myTurtles[number].forward(10)

def right(number):
    myTurtles[number].setheading(0)
    myTurtles[number].forward(10)

def restart():
   
    myTurtles[0].setposition(400, -300)
    myTurtles[0].setheading(90)
    myTurtles[1].setposition(-400, -300)
    myTurtles[1].setheading(90)
    
    bet = screen.textinput("Choose your bet", "Enter blue or green: ")
    screen.listen()
    
    speed = random.randint(0, 2)
    while myTurtles[0].ycor() < 300 and myTurtles[0].ycor() < 300:
        if speed < 2: # randint(0, 2) can gives 0, 1, 2  
            up(speed)
        speed = random.randint(0, 2)

    if myTurtles[0].ycor() == 300:
        if bet == "blue":
            messagebox.showinfo("Result", "Blue is the winner\n\nYou win!")
        else:
            messagebox.showinfo("Result", "Blue is the winner\n\nYou lost")
    else:
        if bet == "green":
            messagebox.showinfo("Result", "Green is the winner\n\nYou win!")
        else:
            messagebox.showinfo("Result", "Green is the winner\n\nYou lost")
    
# --- main ---

screen = turtle.Screen()
screen.title("Turtle race")

myTurtles = [
    turtle.Turtle(),
    turtle.Turtle(),
]    

myTurtles[0].shape("turtle")
myTurtles[1].shape("turtle")

turtle.onkey(lambda: up(0),    'Up')
turtle.onkey(lambda: down(0),  'Down')
turtle.onkey(lambda: left(0),  'Left')
turtle.onkey(lambda: right(0), 'Right')

turtle.onkey(lambda: up(1),    'w')
turtle.onkey(lambda: down(1),  's')
turtle.onkey(lambda: left(1),  'a')
turtle.onkey(lambda: right(1), 'd')

turtle.onkey(restart, 'r')

restart()

turtle.mainloop()

我其实也试着找出如何制作一组海龟:) 谢谢!不过我不明白你为什么在.onkey方法中使用了lambda。 - Ron Gerbi
1
onkey needs function's name without () and arguments - it is called "callback". I use lambda to put function with () and arguments. Normally I would have to create function def up0(): up(0) or up0 = lambda:up(0) and then use onkey(up0, 'Up') - furas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接