(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