turtle onclick() method not working as it should - python

The following code creates a window in which a python turtle follows wherever your mouse goes. However, it draws indescriminately of whether the user is clicking to draw or not. My code is the following:
Note: You must have pythonwin installed in order for this program to work properly
import turtle, win32api
while True:
# turtle.penup()
user = win32api.GetCursorPos()
mousepos = [user[0]-510,-1*(user[1])+ 410]
turtle.goto(mousepos)
turtle.onclick(turtle.pendown())
In theory, this would only draw when the user is pressing and holding the mouse, but it doesn't work in practice. The commented code will simply cause it to not draw at all. Any advice?

turtle.onclick(turtle.pendown())
Here, you are calling pendown(), which returns probably None; then you're passing this None to onclick(). It probably means "do nothing on a click". That's probably not what you want.
According to #Gibby's comment, you want:
def clicked(*args): # args ignored
turtle.pendown()
turtle.onclick(clicked)

Related

Turtle Screen.tracer(0) doesn't stop all animation

I thought using Screen.tracer(0) disabled animation in Python Turtle Graphics. However in the following program, if you comment out screen.update(), there is still some animation happening - the turtle trail gets drawn although the turtle doesn't "move" (or get updated). What is happening here please? Is there way to make updating the screen completely manual?
import turtle
def move():
my_turtle.forward(1)
my_turtle.right(1)
screen.update() # Comment out this line to see issue.
screen.ontimer(move, 10)
screen = turtle.Screen()
my_turtle = turtle.Turtle()
my_turtle.shape("turtle")
screen.tracer(0)
move()
turtle.done()
No, screen.tracer(0) doesn't stop all animation. Some turtle commands like end_fill() invoke screen.update() directly, some like dot() invoke it due to other methods that they in turn invoke. You only advise the system when you call update(), not control it completely.
Put your update() calls where you believe you need them, and don't assume certain methods force an update, otherwise future updates of turtle might break your code. (I.e. someone might actually fix turtle.)
For potentially helpful details, see my tracer() rules of thumb and information about the first argument's numeric value
In turtle.py, forward() calls _go() which sets an endpoint, then calls _goto()
_goto() creates a newline if line segments get above 42
if len(self.currentLine) > 42: # 42! answer to the ultimate question
# of life, the universe and everything
self._newLine()
The value appears to be arbitrary; you could set it to something higher, but then there are pauses where nothing appears to be happening.
def _newLine(self, usePos=True):
"""Closes current line item and starts a new one.
Remark: if current line became too long, animation
performance (via _drawline) slowed down considerably.
"""

Re-open turtle after turtle.bye()

I have some code as follows:
# My code here
turtle.bye()
After that, is there any way I can reopen the turtle window.
I know you can do turtle.clearscreen() but that does not close the turtle window.
I will accept any answer which allows me to close the turtle graphics window and then reopen it without opening and running another python program to do this.
Thank you in advance
I've seen situations where the approach of #LukeTimmons worked but not always reliably and not in every situation. Give this solution a try:
import time
import turtle
turtle.dot(200, 'green')
time.sleep(2)
turtle.bye()
# These two lines (indirectly) resurrect turtle environment after turtle.bye()
turtle.Turtle._screen = None # force recreation of singleton Screen object
turtle.TurtleScreen._RUNNING = True # only set upon TurtleScreen() definition
turtle.dot(200, 'red')
turtle.mainloop()
It resets two flags that keep turtle from starting up again. It may be safer to create your own turtle after restart rather than use the default turtle which may point back to the departed environment.
There may be other ways but this is the only way I know.
from turtle import *
def turtle1():
#Your code here
turtle1()
turtle.bye()
turtle1()
This should re-run your code without re-typing it.

Python script to control mouse clicks

I created a small Python script using win32api to use on the popular game Cookie Clicker (a game where you have to click on a Big Cookie to gain points) just for fun. It has a function called "auto_clicker" that do just that: keeps clicking on the screen on the point the user defined. This is the script:
# -*- coding: utf-8 -*-
import win32con
import win32api
def clicker(x,y):
"""Clicks on given position x,y
Input:
x -- Horizontal position in pixels, starts from top-left position
y -- Vertical position in pixels, start from top-left position
"""
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)
def auto_clicker(x = -1,y = -1):
"""Keep clicking on position x,y. If no input is given, gets from actual
mouse position.
"""
if x == -1 | y == -1:
x,y = win32api.GetCursorPos()
while True:
clicker(x,y)
It works nicely, but I want to make some improvements:
How can I get the cursor position only when the user clicks instead when the function is called? I would prefer to not add another module
since win32api seems to contain everything I needed. Tried this
method without success.
How can I detect a keypress like "Escape", so I can exit from my program without the ugly hack I am using now (Ctrl+Alt+Del seems to give SetCursorPos denied access, so Python throws a error and exit the program).
Can I make this program portable? Seems like I can do using Tkinter and generating a invisible Tk window, but I tried to write something without success.
I don't think with win32api you can listen to clicks you can just generate them (not sure though). However, try using pyHook, it's a simple api easy to use and can be found here http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=Main_Page. With pyhook you can create a listener to listen to a mouse event and upon a mouse click you can do whatever you want, the example in the link shows you how. As for key press, you can use the same api for that too, also an example is provided, good luck!
use pynput . It can control mouse, keyboard, etc.
examples:
from pynput.mouse import Button, Controller
mouse = Controller()
# Read pointer position
print('The current pointer position is {0}'.format(
mouse.position))
# Set pointer position
mouse.position = (10, 20)
print('Now we have moved it to {0}'.format(
mouse.position))
# Move pointer relative to current position
mouse.move(5, -5)
# Press and release
mouse.press(Button.left)
mouse.release(Button.left)
# Double click; this is different from pressing and releasing
# twice on Mac OSX
mouse.click(Button.left, 2)
# Scroll two steps down
mouse.scroll(0, 2)

Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates

I'm trying to get the mouse position through Python turtle. Everything works except that I cannot get the turtle to jump to the position of the mouse click.
import turtle
def startmap(): #the next methods pertain to drawing the map
screen.bgcolor("#101010")
screen.title("Welcome, Commadore.")
screen.setup(1000,600,1,-1)
screen.setworldcoordinates(0,600,1000,0)
drawcontinents() #draws a bunch of stuff, works as it should but not really important to the question
turtle.pu()
turtle.onclick(turtle.goto)
print(turtle.xcor(),turtle.ycor())
screen.listen()
As I understand, the line that says 'turtle.onclick(turtle.goto)' should send the turtle to wherever I click the mouse, but it does not. The print line is a test, but it only ever returns the position that I sent the turtle last, nominally (0, 650) although this does not have major significance.
I tried looking up tutorials and in the pydoc, but so far I have not been able to write this successfully.
I appreciate your help. Thank you.
Edit: I need the turtle to go to the click position(done) but I also need it to print the coordinates.
You are looking for onscreenclick(). It is a method of TurtleScreen. The onclick() method of a Turtle refers to mouse clicks on the turtle itself. Confusingly, the onclick() method of TurtleScreen is the same thing as its onscreenclick() method.
24.5.4.3. Using screen events¶
turtle.onclick(fun, btn=1, add=None)
turtle.onscreenclick(fun, btn=1, add=None)¶
Parameters:
fun – a function with two arguments which will be called with the coordinates of the clicked point on the canvas
num – number of the mouse-button, defaults to 1 (left mouse button)
add – True or False – if True, a new binding will be added, otherwise it will replace a former binding
Bind fun to mouse-click events on this screen. If fun is None, existing bindings are removed.
Example for a TurtleScreen instance named screen and a Turtle instance named turtle:
>>> screen.onclick(turtle.goto) # Subsequently clicking into the TurtleScreen will
>>> # make the turtle move to the clicked point.
>>> screen.onclick(None) # remove event binding again
Note: This TurtleScreen method is available as a global function only under the name onscreenclick. The global function onclick is another one derived from the Turtle method onclick.
Cutting to the quick...
So, just invoke the method of screen and not turtle. It is as simple as changing it to:
screen.onscreenclick(turtle.goto)
If you had typed turtle.onclick(lambda x, y: fd(100)) (or something like that) you would probably have seen the turtle move forward when you clicked on it. With goto as the fun argument, you would see the turtle go to... its own location.
Printing every time you move
If you want to print every time you move, you should define your own function which will do that as well as tell the turtle to go somewhere. I think this will work because turtle is a singleton.
def gotoandprint(x, y):
gotoresult = turtle.goto(x, y)
print(turtle.xcor(), turtle.ycor())
return gotoresult
screen.onscreenclick(gotoandprint)
If turtle.goto() returns None (I wouldn't know), then you can actually do this:
screen.onscreenclick(lambda x, y: turtle.goto(x, y) or print(turtle.xcor(), turtle.ycor())
Let me know if this works. I don't have tk on my computer so I can't test this.

How To Make Mini Example For DrawingArea Display Something

I've written a mini example for DrawingArea which, when started, displays nothing. If I insert a raw_input() just for waiting for a keyboard press at a specific place, it functions, so this is a workaround. Here's the code:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
R = 300
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_default_size(R, R)
drawing_area = gtk.DrawingArea()
window.add(drawing_area)
window.show_all()
gc = drawing_area.get_style().fg_gc[gtk.STATE_NORMAL]
if 0:
raw_input()
drawing_area.window.draw_line(gc, R/10, R/10, R*9/10, R*9/10)
raw_input()
This version doesn't display the drawn line in the opening window; upon pressing enter in the shell, it will just terminate (and remove the window). But if I enable the raw_input() at the if 0: block, it waits twice for an enter in the shell and between the two enters it will display the drawn line (so in general the code works, it seems to be just a weird refresh problem).
I also tried to flush the event queue of GTK using this snippet:
while gtk.events_pending(): # drain the event pipe
gtk.main_iteration()
I inserted it at various places, always to no avail.
I also tried the usual gtk.main() as the last command in the script (of course). But it also didn't help.
How do I do this correctly and why is that raw_input() having that strange side-effect?
You should connect to your drawing area's expose-event signal. That is the only place that you should try to draw on the drawing area; the reason for this is that anything you draw is erased again when the window is minimized or another window moves over it. However, the expose event always happens at the right time so you can keep the drawing up-to-date whenever it is needed.
Like this:
def on_drawing_area_expose(drawing_area, event, data=None):
# ... do your drawing here ...
drawing_area.connect('expose-event', on_drawing_area_expose)
Also check out drawing with Cairo, which is the preferred and more flexible way. Here is a tutorial.

Categories