3

I would like to make a program that creates a turtle window that the user can click 4 times to create an irregular polygon. It will automatically go back to the starting point after the 4th click to make sure that it is properly closed. That much works great, but the problem is that I would like to have it filled in as well, which I can't get to work.

import turtle


class TrackingTurtle(turtle.Turtle):
    """ A custom turtle class with the ability to go to a mouse
    click location and keep track of the number of clicks """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.count = 0

    def goto_mouse(self, x, y):
        """ Go to the given (x, y) coordinates, or go back
        to the starting place after the 4th click """
        if self.count <= 4:
            self.goto(x, y)
            self.count += 1
            if self.count == 4:
                self.goto(0, 0)
                turtle.done()


if __name__ == "__main__":
    turtle.setup(1080, 720)

    wn = turtle.Screen()
    wn.title("Polygon Fun")

    turt = TrackingTurtle()
    turt.hideturtle()

    turt.fillcolor("#0000ff")
    turt.begin_fill()
    turtle.onscreenclick(alex.goto_mouse)
    
    turt.end_fill()

    wn.mainloop()

Example output

I would like the above output to be filled in blue, but as you can see it's not. Is this possible with the turtle module? If so what might I change to fix it? Thanks in advance for your time and help!

AceSoap19
  • 31
  • 2
  • 2
    You have to delay the call to `.end_fill()` until *after* all of the points have been drawn - you're currently doing it immediately after `.begin_fill()`, so there's nothing to be filled. (`.onscreenclick()` doesn't wait for clicks to happen, it just specifies what will happen later if a click occurs.) – jasonharper Mar 16 '22 at 18:12
  • Ok how could I delay the call then? I guess I could use `time.sleep()`, but that would mean that it wouldn't fill until after the time ran out, and there would be a delay otherwise. Is there something better that I could do or is that my only option? – AceSoap19 Mar 16 '22 at 18:28
  • 1
    You would call it just after drawing the final point - you already have an `if` statement handling that condition, move the call there. – jasonharper Mar 16 '22 at 18:30
  • I actually just tried that and it works great! Thanks! – AceSoap19 Mar 16 '22 at 18:31

1 Answers1

0

You're pretty close. The misunderstanding seems to be thinking that onscreenclick blocks until the shape is done, then end_fill() runs. Actually, onscreenclick returns immediately after registering the click handler, then .end_fill() runs before any clicks have occurred or the turtle main loop runs. By the time the user starts clicking, the fill has long been closed.

The solution is to move the .end_fill() call to the if self.count == 4: block.

Since I'm not a fan of inheriting Turtle, here's a similar, minimal example that uses a closure but should be readily adaptable to your use case.

import turtle

def track_polygon(sides=5):
    def goto_mouse(x, y):
        nonlocal clicks

        if clicks < sides - 1:
            turtle.goto(x, y)
            clicks += 1

            if clicks >= sides - 1:
                turtle.goto(0, 0)
                turtle.end_fill()
                turtle.exitonclick()

    clicks = 0
    turtle.begin_fill()
    turtle.onscreenclick(goto_mouse)

track_polygon()
turtle.mainloop()
ggorlen
  • 44,755
  • 7
  • 76
  • 106