Having read...
How can I log key presses using turtle?
I am trying to detect key presses using a slightly different method.
Here is a simplified version of my code, which works as expected...
from turtle import *
WIDTH, HEIGHT = 500, 500
screen = Screen()
screen.setup(WIDTH, HEIGHT)
bgcolor('grey')
ht()
pu()
def checka():
write('a')
fd(10)
def checkb():
write('b')
fd(10)
screen.onkey(checka, 'a')
screen.onkey(checkb, 'b')
screen.listen()
screen.mainloop()
However I wish to handle key presses for all letters of the alphabet, so tried this...
from turtle import *
WIDTH, HEIGHT = 500, 500
screen = Screen()
screen.setup(WIDTH, HEIGHT)
bgcolor('grey')
ht()
pu()
def check(l):
write(l)
fd(10)
screen.onkey(check('a'), 'a')
screen.onkey(check('b'), 'b')
screen.listen()
screen.mainloop()
But this code does not work. Can anyone shed any light on what is happening here or suggest an alternative (but as simple) method of achieving the same?
The
screen.onkey()function expects a function as input. In your first example you do this correctly (screen.onkey(checka, 'a')), but in the second example, you call the function before you pass it (screen.onkey(check('a'), 'a'). This means that you are passing the return value of thecheckfunction, not the function itself.Your check function doesn't have any
returnstatements in that return a value explicitly. In Python, functions that don't return a value explicitly returnNone. So you are in effect callingscreen.onkey(None, 'a'), which I am guessing does not have any effect.To fix this, you can use a closure - a function inside a function. With closures, the inner function can use variables available to the outer function, which means you can make check functions for any letter.
Or, as quamrana suggests, you can do the same thing with less code by using lambda functions.
--EDIT--
To add functions for all of the letters in the alphabet, you can use a for loop. Conveniently, Python has already defined a string containing all the lowercase ASCII characters at string.ascii_lowercase, so we can use that to loop over.
Here, the body of the for loop will be run once for each character in the string, and the value of
lwill be that character. This has the effect of runningscreen.onkey(make_check_func('a'), 'a'), thenscreen.onkey(make_check_func('b'), 'b'), all the way through toscreen.onkey(make_check_func('z'), 'z').Note that using
screen.onkey(lambda: check(l), l)inside the for loop will not work, as the value oflthat the lambda function "remembers" will be always be "z". See the common gotchas entry for an explanation.