【问题标题】:Python turtle ondrag event vs. compound shapesPython turtle ondrag 事件与复合形状
【发布时间】:2017-04-03 04:04:59
【问题描述】:

当我注册一个多边形或只有一个组件的复合形状时,我可以使用该形状创建一个海龟光标,添加一个拖动事件处理程序,并将其拖动到屏幕上。

但是当我使用第二个组件注册复合形状时,我不能再拖动它:

from turtle import Turtle, Screen, Shape

def simple_polygon(turtle):

    turtle.begin_poly()
    turtle.circle(50)
    turtle.end_poly()
    screen.register_shape("simple_polygon", turtle.get_poly())

    turtle.reset()

def compound_single(turtle):

    shape = Shape("compound")

    turtle.begin_poly()
    turtle.circle(50)
    turtle.end_poly()
    shape.addcomponent(turtle.get_poly(), "blue", "blue")  # component #1
    screen.register_shape("compound_single", shape)

    turtle.reset()

def compound_double(turtle):

    shape = Shape("compound")

    turtle.begin_poly()
    turtle.circle(50)
    turtle.end_poly()
    shape.addcomponent(turtle.get_poly(), "green", "green")  # component #1

    turtle.penup()
    turtle.left(90)
    turtle.forward(25)
    turtle.right(90)
    turtle.pendown()

    turtle.begin_poly()
    turtle.circle(25)
    turtle.end_poly()
    shape.addcomponent(turtle.get_poly(), "yellow", "yellow")  # component #2
    screen.register_shape("compound_double", shape)

    turtle.reset()

def drag_handler(turtle, x, y):
    turtle.ondrag(None)  # disable ondrag event inside drag_handler
    turtle.goto(x, y)
    turtle.ondrag(lambda x, y, turtle=turtle: drag_handler(turtle, x, y))

screen = Screen()

magic_marker = Turtle()
simple_polygon(magic_marker)
compound_single(magic_marker)
compound_double(magic_marker)
magic_marker.hideturtle()

red = Turtle(shape="simple_polygon")
red.color("red")
red.penup()
red.goto(150, 150)
red.ondrag(lambda x, y: drag_handler(red, x, y))

blue = Turtle(shape="compound_single")
blue.penup()
blue.goto(-150, -150)
blue.ondrag(lambda x, y: drag_handler(blue, x, y))

mostly_green = Turtle(shape="compound_double")
mostly_green.penup()
mostly_green.goto(150, -150)
mostly_green.ondrag(lambda x, y: drag_handler(mostly_green, x, y))

screen.mainloop()

您会发现生成的三个形状中只有两个可以拖动。注释掉这一行:

shape.addcomponent(turtle.get_poly(), "yellow", "yellow")  # component #2

第三个圆圈将全是绿色并且可以拖动。

我在海龟文档中找不到关于具有多个组件的复合形状在拖动时不是有效光标的任何提及。第二个组件完全在第一个组件之内、重叠还是在第一个组件之外都没有任何区别。

查看海龟代码,我看不出有什么区别,这让我相信这个问题出在 tkinter 基础中,并且没有在海龟中正确记录。这个问题是 Unix 还是 OSX 特有的?

我错过了什么吗?为什么我不能拖动由多个组件构建的光标?

【问题讨论】:

    标签: python turtle-graphics


    【解决方案1】:

    我最近也遇到了这个问题,很高兴找到你的问题,cdlane,以确认我不仅仅是在想象 - Python 的海龟模块中实际上可能存在错误。

    我在 Python 错误跟踪器中查找了该问题,谢天谢地,有人已经发现了问题并且其他人已经提交了补丁: https://bugs.python.org/issue16428

    虽然在撰写本文时该补丁尚未合并到 Python 中,但我尝试修改已安装的 Python 版本以合并该补丁,并且成功了。

    如果您不想对已安装的 Python 进行更改,您可以直接在代码中修改海龟对象以将补丁合并,如下所示:

    [请注意,为了提高性能,我稍微修改了您的代码,添加了 tracer(0) 和 update();但是,该补丁可以在没有这些添加的情况下工作。]

    from turtle import Turtle, Screen, Shape, tracer, update
    
    #### Monkey patch Turtle object to allow compound shapes to be dragged. ####
    ####### Based on patch by Ingrid: https://bugs.python.org/issue16428 #######
    
    def onclick(self, fun, btn=1, add=None):
        if (self.turtle._type == 'compound'):
            for i in self.turtle._item:
                self.screen._onclick(i, fun, btn, add)
        else:
            self.screen._onclick(self.turtle._item, fun, btn, add)
        self._update()
    
    Turtle.onclick = onclick
    
    def onrelease(self, fun, btn=1, add=None):
        if (self.turtle._type == 'compound'):
            for i in self.turtle._item:
                self.screen._onrelease(i, fun, btn, add)
        else:
            self.screen._onrelease(self.turtle._item, fun, btn, add)
        self._update()
    
    Turtle.onrelease = onrelease
    
    def ondrag(self, fun, btn=1, add=None):
        if (self.turtle._type == 'compound'):
            for i in self.turtle._item:
                self.screen._ondrag(i, fun, btn, add)
        else:
            self.screen._ondrag(self.turtle._item, fun, btn, add)
    
    Turtle.ondrag = ondrag
    
    ############################ End Monkey patch. #############################
    
    def simple_polygon(turtle):
    
        turtle.begin_poly()
        turtle.circle(50)
        turtle.end_poly()
        screen.register_shape("simple_polygon", turtle.get_poly())
    
        turtle.reset()
    
    def compound_single(turtle):
    
        shape = Shape("compound")
    
        turtle.begin_poly()
        turtle.circle(50)
        turtle.end_poly()
        shape.addcomponent(turtle.get_poly(), "blue", "blue")  # component #1
        screen.register_shape("compound_single", shape)
    
        turtle.reset()
    
    def compound_double(turtle):
    
        shape = Shape("compound")
    
        turtle.begin_poly()
        turtle.circle(50)
        turtle.end_poly()
        shape.addcomponent(turtle.get_poly(), "green", "green")  # component #1
    
        turtle.penup()
        turtle.left(90)
        turtle.forward(25)
        turtle.right(90)
        turtle.pendown()
    
        turtle.begin_poly()
        turtle.circle(25)
        turtle.end_poly()
        shape.addcomponent(turtle.get_poly(), "yellow", "yellow")  # component #2
        screen.register_shape("compound_double", shape)
    
        turtle.reset()
    
    def drag_handler(turtle, x, y):
        turtle.ondrag(None)  # disable ondrag event inside drag_handler
        turtle.goto(x, y)
        update()
        turtle.ondrag(lambda x, y, turtle=turtle: drag_handler(turtle, x, y))
    
    screen = Screen()
    tracer(0)
    
    magic_marker = Turtle()
    simple_polygon(magic_marker)
    compound_single(magic_marker)
    compound_double(magic_marker)
    magic_marker.hideturtle()
    
    red = Turtle(shape="simple_polygon")
    red.color("red")
    red.penup()
    red.goto(150, 150)
    red.ondrag(lambda x, y: drag_handler(red, x, y))
    
    blue = Turtle(shape="compound_single")
    blue.penup()
    blue.goto(-150, -150)
    blue.ondrag(lambda x, y: drag_handler(blue, x, y))
    
    mostly_green = Turtle(shape="compound_double")
    mostly_green.penup()
    mostly_green.goto(150, -150)
    mostly_green.ondrag(lambda x, y: drag_handler(mostly_green, x, y))
    update()
    screen.mainloop()
    

    【讨论】:

    • 感谢您提供详细信息和补丁。我想知道它是否会在原始错误报告发布 10 周年之前发布 Python!
    • 不客气,@cdlane。随着 Python 在过去十年中发生的所有变化,我很感激turtle 模块仍然存在。核心开发人员有很多事情要做,所以我不指望这个错误很快就会取得进展。
    【解决方案2】:

    我认为当你拖动一个对象时,整个画布都在移动,看起来就像在移动一样。

    同样的事情也发生在 Canvas Tkinter 中。 当您对单击对象时发生的事情进行编程时,整个画布都在等待单击。所以这意味着如果两个对象有一个 onclick 事件,整个事情都不会工作。

    希望这会有所帮助!

    【讨论】:

    • 我不能说你的回答有帮助,我什至不能理解它。您是否运行了我提供的示例代码(有和没有编辑)来查看问题的实际效果?
    • 我做了,我想我知道发生了什么我会编辑我的 answer@cdlane
    • 等一下@cdlane,您将绿色形状定义为一个整体形状还是两个形状?这可能很重要。
    • 蓝色和绿色形状都是复合形状。蓝色形状是一种元素的复合形状,绿色形状是两种元素的复合形状。红色形状不是复合形状。蓝色和红色形状的行为相同。
    • 您只是重申了所提出的问题。我已经知道两种颜色不能拖动,问题是为什么?我建议你删除你的答案并在你对定义海龟光标、复合形状和底层 tkinter 库有一定的经验后重新考虑这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多