基于计时器的迭代期间可重置Python重置

问题描述 投票:0回答:2

在完成路径之前,单击下面程序中的reset按钮,我会遇到一些奇怪的行为。当我这样做时,乌龟会加速并不稳定地移动,同时基本上仍会紧贴小路。我按reset的次数越多,机芯变得越发呆。

有人可以解释一下如何使reset按钮完全重置路径并避免上述问题吗?

import turtle
import tkinter as tk

def create_reset_button_tkinter():
    """An alternative approach to creating a button using Tkinter."""
    canvas = screen.getcanvas()
    button = tk.Button(canvas.master, text="Reset", background="green", foreground="white", bd=0,
                       activebackground="green", activeforeground="white", command=reset)
    canvas.create_window(-100, 100, window=button)

def reset():
    global path_iter
    bob.goto(0, 0)
    path = [(0, 0), (20, 0), (20, 20), (20, 30), (30, 20), (40, 20), (40, 30), (50, 30), (60, 30), (60, 40)]
    path_iter = iter(path)
    go_to_next_coord()


def go_to_next_coord():
    try:
        next_coord = next(path_iter)
    except StopIteration:
        return
    bob.goto(next_coord)
    turtle.ontimer(go_to_next_coord, 500)


screen = turtle.Screen()
create_reset_button_tkinter()
bob = turtle.Turtle("square")
bob.penup()
path = [(0, 0), (20, 0), (20, 20), (20, 30), (30, 20), (40, 20), (40, 30), (50, 30), (60, 30), (60, 40)]
path_iter = iter(path)
go_to_next_coord()

turtle.done()

python tkinter turtle-graphics iterable
2个回答
0
投票

[您可以在Reset()函数中检查当前迭代器中是否还有项目,如果没有,请调用go_to_next_coord()重新启动海龟计时器:

def reset():
    global path_iter
    num_of_items = len(list(path_iter)) # get the number of items in current iterator
    #bob.goto(0, 0)  # no need to call here as it will be executed in next call of go_to_next_coord()
    path = [(0, 0), (20, 0), (20, 20), (20, 30), (30, 20), (40, 20), (40, 30), (50, 30), (60, 30), (60, 40)]
    path_iter = iter(path)
    if num_of_items == 0:
        # restart turtle timer
        go_to_next_coord()

0
投票

我尚不清楚使用iter有什么好处,特别是当@ acw1668对代码的修复必须将iter转换回list时:

num_of_items = len(list(path_iter))

为什么不首先使用list

from turtle import Screen, Turtle
from tkinter import Button

PATH = [ \
    (0, 0), (20, 0), (20, 20), (20, 30), (30, 20), \
    (40, 20), (40, 30), (50, 30), (60, 30), (60, 40), \
]

semaphore = 0

def reset():
    global semaphore

    if semaphore:
        return  # reset already executing when 'Reset' pressed

    semaphore += 1
    empty = len(path_list) == 0

    path_list[:] = PATH  # reload path coordinates

    turtle.home()

    if empty:
        screen.ontimer(go_to_next_coord)  # execute shortly after this function exits

    semaphore -= 1

def go_to_next_coord():
    if not semaphore:
        try:
            turtle.goto(path_list.pop(0))
        except IndexError:
            return

    screen.ontimer(go_to_next_coord, 500)

def create_reset_button_tkinter():
    """ An alternative approach to creating a button using Tkinter. """

    canvas = screen.getcanvas()
    button = Button(canvas.master, text="Reset", command=reset)

    canvas.create_window(-100, 100, window=button)

screen = Screen()

create_reset_button_tkinter()

turtle = Turtle("square")
turtle.penup()

path_list = list(PATH)

go_to_next_coord()

screen.mainloop()

我发现在两个实现中仍然可能导致行为不正确的两个问题:首先,go_to_next_coord()可以在reset()方法期间执行。 (例如,当您要求乌龟做某事时,这会短暂地将控制权移交给事件处理程序,并允许计时器触发。)这会引起罕见的意外视觉故障。

[其次,如果按钮是由乌龟onclick()触发的,我通常会取消设置事件处理程序代码内的事件处理程序映射(直到返回之前),以防止事件[[stacking。但是,由于这是一个tkinter按钮,因此这超出了Turtle的控制范围。 (一遍又一遍地按“重置”。)

为了缓解这两个问题,我引入了简单的semaphore变量。 (尽管您也可以通过tkinter命令禁用和重新启用按钮事件。)不够完美,但是更好。
© www.soinside.com 2019 - 2024. All rights reserved.