1

我正在尝试使用 python 3 乌龟图形来做演示软件之类的事情:画一些东西,暂停击键以便演示者可以解释,然后画下一个东西。

这是我尝试过的一种解决方案(不起作用):

import turtle
import time

paused = False

def unpause():
    print("unpause() called")
    global paused
    paused = False

def pause():
    global paused
    paused = True
    while paused:
        time.sleep(0.1)


t = turtle.Turtle()

# set up listener
t.screen.listen()
t.screen.onkeypress(unpause)

# draw something
t.hideturtle()
t.pensize(5)
t.speed(1)
t.pu()
t.goto(-300,-300)
t.pd()
t.goto(-300, 300)

# pause until key is pressed
pause()

# draw some more
t.pu()
t.goto(300,-300)
t.pd()
t.goto(300, 300)

t.screen.mainloop()

问题是睡眠调用循环完全阻止了按键被检测到,即使我使用了一个非常短(100 毫秒)睡眠的 while 循环。

如果我在绘制第一行时按了一个键,我会在控制台中看到“unpause() called”,因此我知道键绑定处于活动状态。

为什么没有检测到按键?我不知道内部原理,但我认为击键会记录在某个缓冲区中,并且在睡眠调用之间的休息期间,侦听器将读取缓冲区并取消设置paused全局变量。这没有发生。

还有其他方法可以实现吗?

这是在 Debian Linux 系统上。

4

3 回答 3

0

采纳您的建议给我的想法(感谢 martineau 和 kederrac!)我能够想出一个解决方案。它涉及将我的每个绘图任务包装在一个函数中,然后使用一个调度函数,该函数要么等待带有ontimer循环的按键,要么调用下一个绘图函数。

这个概念验证代码完全使用了太多的全局变量,但它展示了这种技术:

import turtle

t = turtle.Turtle()
paused = False
current_task = 0

def unpause():
    global paused
    paused = False

def turtle_setup():
    global t
    t.screen.onkeypress(unpause)
    t.screen.listen()
    t.hideturtle()
    t.pensize(5)
    t.speed(1)

def draw_task_finished():
    global paused, current_task, drawing_tasks
    current_task += 1
    paused = True
    if current_task < len(drawing_tasks):
        draw_task_after_keypress()

def draw_task_after_keypress():
    global paused, current_task
    if paused:
        turtle.ontimer(draw_task_after_keypress, 100)
    else:
        drawing_tasks[current_task]()

def draw_thing_one():
    global t
    t.pu()
    t.goto(-300,-300)
    t.pd()
    t.goto(-300, 300)
    draw_task_finished()

def draw_thing_two():
    global t
    t.pu()
    t.goto(300,-300)
    t.pd()
    t.goto(300, 300)
    draw_task_finished()

drawing_tasks = [draw_thing_one, draw_thing_two]

turtle_setup()
drawing_tasks[0]()

t.screen.mainloop()
于 2020-03-29T22:08:26.393 回答
0

Turtle 图形基于tkinter,这是一个事件驱动的 GUI 框架,因此您不能像在常规的程序驱动程序中那样做事情——请参阅@Bryan Oakley 对Tkinter 问题的回答——随着时间的推移执行函数以获得更多信息详细说明(尽管该turtle模块隐藏了大部分这些细节)。无论如何,这个事实意味着你不应该time.sleep()在这样一个紧密的循环中调用,因为一切都必须在不干扰mainloop().

避免调用的“技巧”time.sleep()是使用该函数安排对全局变量的定期检查turtle.ontimer()——因此如果它的第一部分发生更改,您的程序将可以工作,如下所示:

import turtle

paused = False

def unpause():
    print("unpause() called")
    global paused
    paused = False

def pause():
    global paused
    paused = True
    pausing()  # Start watching for global to be changed.

def pausing():
    if paused:
        turtle.ontimer(pausing, 250)  # Check again after delay.
    # else quit checking.

t = turtle.Turtle()

# set up listener
t.screen.onkeypress(unpause)  # Reversed order of
t.screen.listen()             # these two statements.

# draw something
t.hideturtle()
t.pensize(5)
t.speed(1)
t.pu()
t.goto(-300,-300)
t.pd()
t.goto(-300, 300)

# pause until key is pressed
pause()

# draw some more
t.pu()
t.goto(300,-300)
t.pd()
t.goto(300, 300)

t.screen.mainloop()
于 2020-03-29T18:47:10.537 回答
0

你可以使用turtle.done()function. 只需做一个input() 函数,如果输入了,程序就会运行。我用基本方法尝试了这个。

于 2021-10-09T06:27:02.703 回答