Я вижу несколько проблем с вашим кодом:
Вы смешиваете объектно-ориентированный интерфейс с черепахой
функциональный интерфейс к этому модулю. Я рекомендую один или
другой, но не оба. См. Мое import
изменение, чтобы принудительно только OOP.
Вы используете низкоуровневые события мыши и клавиш tkinter вместо
собственные события черепахи. Я рекомендую вам попробовать работать на уровне черепах
(хотя это вносит сбой по сравнению с вашей реализацией, см.
ниже.)
Вы вводите непреднамеренную рекурсию, не отключая события
внутри ваших обработчиков событий. Отключение событий внутри этих обработчиков
это займет значительное время, чтобы очистить вашу графику.
Вот моя переделка вашего кода по приведенным выше строкам. Единственный сбой в том, что в отличие от вашего оригинала, «переместить черепаху здесь» и «начать перетаскивание» займет два клика, один щелчок на экране, чтобы переместить черепаху в текущее местоположение, и один щелчок черепахи, чтобы начать перетаскивание. Это связано с различиями в интерфейсе, который Turtle предоставляет для событий tkinter. (Python 3 немного лучше в этом отношении, но не для этой ситуации.)
Чтобы облегчить это, я использовал больший черепаховый курсор. Я также добавил логику заголовка:
from turtle import Turtle, Screen, mainloop
WIDTH = 600
HEIGHT = 300
def gothere(x, y):
screen.onscreenclick(gothere) # disable events inside handler
turtle.penup()
print("gothere (%d,%d)" % (x, y))
turtle.goto(x, y)
turtle.pendown()
screen.onscreenclick(gothere)
def movearound(x, y):
turtle.ondrag(None) # disable events inside handler
turtle.setheading(turtle.towards(x, y))
print("movearound (%d,%d)" % (x, y))
turtle.goto(x, y)
turtle.ondrag(movearound)
def release(x, y):
print("release (%d,%d)" % (x, y))
turtle.penup()
def reset():
print("reset")
turtle.clear()
screen = Screen()
screen.setup(WIDTH, HEIGHT)
# screen.setworldcoordinates(0, HEIGHT, WIDTH, 0) # should work fine either way
turtle = Turtle('turtle')
turtle.speed('fastest')
turtle.ondrag(movearound)
turtle.onrelease(release)
screen.onscreenclick(gothere)
screen.onkey(reset, "Escape")
screen.listen()
mainloop() # normally screen.mainloop() but not in Python 2
Но также посмотрите этот ответ , где я покажу, как сделать событие tkinter onmove
доступным для черепахи.
... ограничение "переместить сюда", а затем "начать перетаскивание" очень не
удобно для пользователя? Как мы можем улучшить это?
Комбинируя мой приведенный выше код с моим альтернативным ответом, на который я ссылался, мы получаем решение, аналогичное тому, с которого вы начали, но без сбоев и в более черепахоподобном стиле:
from turtle import Turtle, Screen, mainloop
from functools import partial
WIDTH = 600
HEIGHT = 300
VERBOSE = False
def onscreenmove(self, fun, btn=1, add=None): # method missing from turtle.py
if fun is None:
self.cv.unbind('<Button%s-Motion>' % btn)
else:
def eventfun(event):
fun(self.cv.canvasx(event.x) / self.xscale, -self.cv.canvasy(event.y) / self.yscale)
self.cv.bind('<Button%s-Motion>' % btn, eventfun, add)
def onscreenrelease(self, fun, btn=1, add=None): # method missing from turtle.py
if fun is None:
self.cv.unbind("<Button%s-ButtonRelease>" % btn)
else:
def eventfun(event):
fun(self.cv.canvasx(event.x) / self.xscale, -self.cv.canvasy(event.y) / self.yscale)
self.cv.bind("<Button%s-ButtonRelease>" % btn, eventfun, add)
def gothere(x, y):
if VERBOSE:
print("gothere (%d,%d)" % (x, y))
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
def movearound(x, y):
screen.onscreenmove(None) # disable events inside handler
if VERBOSE:
print("movearound (%d,%d)" % (x, y))
turtle.setheading(turtle.towards(x, y))
turtle.goto(x, y)
screen.onscreenmove(movearound) # reenable events
def release(x, y):
if VERBOSE:
print("release (%d,%d)" % (x, y))
turtle.penup()
def reset():
if VERBOSE:
print("reset")
turtle.clear()
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.onscreenrelease = partial(onscreenrelease, screen) # install missing methods
screen.onscreenmove = partial(onscreenmove, screen)
turtle = Turtle('turtle')
turtle.speed('fastest')
screen.onscreenclick(gothere)
screen.onscreenrelease(release)
screen.onscreenmove(movearound)
screen.onkey(reset, "Escape")
screen.listen()
mainloop() # normally screen.mainloop() but not in Python 2