gaffer
Posts: 32
Joined: Fri Sep 09, 2016 2:14 am

Turtle.stamp() disables Turtle.onclick() events?

Wed Sep 21, 2016 7:26 am

I've run into some behavior that seems weird to while playing with Python's Turtle library. What I've discovered is that after using Turtle.onclick() to set up event notifications for mouse clicks on the turtle, it fails to work immediately after a Turtle.stamp(). It works fine after any and all other actions so far as I can determine, but the stamp() function effectively disables event notifications until a different turtle command is issued.

(I had originally posted a sample program to demonstrate the behavior and how to work around it by issuing an 'undo'. I came back today (Sept. 22) to update that code with two additional buttons, showing that other turtle commands besides undo() also restore the expected click notification behavior. I attempted to paste the new code over the old within the code block, but screwed up and overwrote not only the code block but my entire first post as well. I apologize for that; I'm rewriting my original post from memory as best I can.)

The sample code demonstrates the problem as outlined in the first paragraph above. When the program begins, the 'stamp' checkbox at the lower right corner of the screen is not enabled. In that state, the user can move the turtle around the screen by clicking locations; the turtle with then rotate to face that direction and move to the clicked point. If the user clicks the turtle itself, the turtle will spin around a couple of times and a prominent message will be displayed in the Python shell window indicating that a turtle click event has been triggered.

If the user checks the 'stamp' checkbox, the turtle will execute a Turtle.stamp() after moving to a clicked location on the screen. It will then become apparent that it is no longer possible to trigger an onclick() event by clicking on the turtle. I've also provided three buttons which allow the user to issue an undo(), fd(0) or left(0) command to the turtle. Using any of them after the turtle has done a stamp() will unblock the onclick() events and allow you to trigger them again by clicking on the turtle.

Here's the demo code:

Code: Select all

# click_and_stamp
"""test program to explore the relationship between turtle clicks,
as enabled by turtle.onclick(), and the turtle.stamp() function.
"""

from turtle import TurtleScreen, RawTurtle, TK

tom = None  # this will be the turtle
turtle_stamp = None  # this will be an IntVar for the 'stamp' checkbox

# initializing function to activate screen clicks
def init_screen_clicks(scrn):
    scrn.onclick(left_click, 1)   # 1 indicates left mouse button
    scrn.listen()

# send the turtle to the location where the mouse was clicked
def send_turtle(t, x, y):
    pos = t.towards(x, y)
    t.setheading(pos)
    t.goto(x, y)
    print('turtle moved to x', x, 'y', y)

# this is the event handler for the left click
def left_click(x, y):
    global tom
    send_turtle(tom, x, y)
    if turtle_stamp.get():
        print('executing turtle.stamp()')
        tom.stamp()

# this is the event handler for turtle clicks
# we should always get a left_click immediately after the turtle click
def click_turtle(x, y):
    global tom
    print('*************  turtle click detected *************')
    tom.left(720) # make it obvious that something happened

# turtle setup
def init_turtle(t):
    t.shape('turtle')
    t.turtlesize(1)
    t.speed(6)
    t.onclick(click_turtle, 1)

# this is the event handler for the undo() button
def turtle_undo():
    global tom
    print('executing turtle.undo()')
    tom.undo()

# this is the event handler for the fd(0) button
def turtle_fd():
    global tom
    print('executing turtle.fd(0)')
    tom.fd(0)

# this is the event handler for the left(0) button
def turtle_left():
    global tom
    print('executing turtle.left(0)')
    tom.left(0)

# here is where we add the undo button and the stamp checkbox
def add_widgets(root):
    global turtle_stamp
    btn_width = 6
    btn_height = 2

    turtle_stamp = TK.IntVar()
    turtle_stamp.set(False)

    btn_undo = TK.Button(root, text='undo()', width=btn_width, \
                        height=btn_height, command=turtle_undo)
    btn_undo.pack(side='left', padx=10, pady=2)

    btn_fd = TK.Button(root, text='fd(0)', width=btn_width, \
                        height=btn_height, command=turtle_fd)
    btn_fd.pack(side='left', padx=10, pady=2)

    btn_left = TK.Button(root, text='left(0)', width=btn_width, \
                        height=btn_height, command=turtle_left)
    btn_left.pack(side='left', padx=10, pady=2)

    chkbox = TK. Checkbutton(root, text='Stamp', variable=turtle_stamp)
    chkbox.pack(side='right', padx=10, pady=2)


# create the canvas
def my_canvas(root, cv_width, cv_height, cv_bg):
    cv = TK.Canvas(root, width=cv_width, height=cv_height, bg=cv_bg)
    cv.pack()
    add_widgets(root)
    return cv


# the following constants determine the dimensions of the game window
scn = None
cv_left   = -200
cv_right  =  200
cv_top    =  150
cv_bottom = -150

cv_width  = abs(cv_left) + cv_right
cv_height = abs(cv_bottom) + cv_top

def main():
    global tom
    root = TK.Tk()
    root.title('Click and Stamp')

    cv = my_canvas(root, cv_width, cv_height, '#ddffff')

    scn = TurtleScreen(cv)
    scn.bgcolor(0.85, 0.85, 1)

    tom = RawTurtle(scn)
    init_turtle(tom)
    init_screen_clicks(scn)

    return 'EVENTLOOP'


if __name__ == '__main__':
    main()
    TK.mainloop()  # keep window open until user closes it
Last edited by gaffer on Thu Sep 22, 2016 9:40 pm, edited 2 times in total.

User avatar
dasmanul
Posts: 502
Joined: Wed Sep 30, 2015 10:20 am
Location: Frankfurt, Germany

Re: Turtle.stamp() disables Turtle.onclick() events?

Wed Sep 21, 2016 7:47 am

My guess would be that the stamp somehow gets placed above the turtle, catches the click and passes it through to the canvas.

Based on that, I thought of the following workaround: In your left_click function, repeat the send_turtle command immediately after the tom.stamp() command. My reasoning was that the last object created at/moved to a certain position might be considered the topmost one. To my surprise, this actually seems to work. ;)

gaffer
Posts: 32
Joined: Fri Sep 09, 2016 2:14 am

Re: Turtle.stamp() disables Turtle.onclick() events?

Wed Sep 21, 2016 3:44 pm

dasmanul wrote:My guess would be that the stamp somehow gets placed above the turtle, catches the click and passes it through to the canvas.

Based on that, I thought of the following workaround: In your left_click function, repeat the send_turtle command immediately after the tom.stamp() command. My reasoning was that the last object created at/moved to a certain position might be considered the topmost one. To my surprise, this actually seems to work. ;)
Thanks, that sounds like a very practical way to deal with it. I was also thinking that the stamp might somehow be 'above' the turtle when I added the 'undo' as a test.

That said, it does appear to be a bug in the turtle library. Is there a formal procedure for submitting it as such to whoever is working on the next version, or is calling attention to it here sufficient?

User avatar
dasmanul
Posts: 502
Joined: Wed Sep 30, 2015 10:20 am
Location: Frankfurt, Germany

Re: Turtle.stamp() disables Turtle.onclick() events?

Wed Sep 21, 2016 4:07 pm

The python documentation at

https://docs.python.org/2/bugs.html

suggests using the python issue tracker at

https://bugs.python.org/

gaffer
Posts: 32
Joined: Fri Sep 09, 2016 2:14 am

Re: Turtle.stamp() disables Turtle.onclick() events?

Wed Sep 21, 2016 11:25 pm

Thanks for those links - I'll post something there.

No doubt you're wondering why I didn't find the links myself. I should have googled 'python bugs'. :oops:

My trouble is that I'm running into things I need to look up faster than I can tick them off the list. I just discovered python two months ago, and that in turn led to the Raspberry Pi. I'm trying to learn about both simultaneously, and that's a lot for an old geezer like me to wrap my head around. I'm thoroughly enjoying it, but it's not my only hobby and finding enough time is the problem. There aren't enough hours in the day.
:D

gaffer
Posts: 32
Joined: Fri Sep 09, 2016 2:14 am

Re: Turtle.stamp() disables Turtle.onclick() events?

Fri Sep 23, 2016 9:20 pm

dasmanul wrote:The python documentation at

https://docs.python.org/2/bugs.html

suggests using the python issue tracker at

https://bugs.python.org/
I've made multiple attempts to register at the python issue tracker site over the past three days. In each case I've completed the form and been shown a "registration in process" page which says this:

Code: Select all

You will shortly receive an email to to confirm your registration. To complete the registration process, visit the link indicated in the email.

Note: if after a few minutes you still haven't received any email, make sure to check the spam folder.
I've yet to get anything back in either my email or my spam bucket. It's impossible to report the bug without registering, and I can't register, so until such time as someone has a suggestion about how to accomplish that I'm finished. Perhaps someone who is already registered there would like to report the issue?

User avatar
dasmanul
Posts: 502
Joined: Wed Sep 30, 2015 10:20 am
Location: Frankfurt, Germany

Re: Turtle.stamp() disables Turtle.onclick() events?

Fri Sep 23, 2016 9:59 pm

I'm not registered there, but from a quick look at the bugtracker site, it looks like you can log in with your Google account. Maybe worth a try?

gaffer
Posts: 32
Joined: Fri Sep 09, 2016 2:14 am

Re: Turtle.stamp() disables Turtle.onclick() events?

Sat Sep 24, 2016 2:46 am

dasmanul wrote:I'm not registered there, but from a quick look at the bugtracker site, it looks like you can log in with your Google account. Maybe worth a try?
To be honest I wanted to set up a fresh account there, with the same user name as here, but with your encouragement I went ahead and did that. We'll see whether it goes anywhere; I'll report back.

It does seem peculiar that their recommended account creation procedure is bogus; it ought to either send you the validation email as advertised or, failing that, a notification as to why the validation was withheld.

Return to “Python”