Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Turtle onkey()
#1
Is there a way to write a turtle onkey() statement so it will listen for any letter key, or can you only specify a single key in each onkey() statement? I want to avoid having 26 onkey(), one set up for each letter "a", "b",... etc.

I want to write a simple tickertape display where every time you type a letter it adds the letter to the end of the string being written by the turtle and moves the display across by one letter.
likes this post
Reply
#2
I don't think the turtle package has a way.

It's built on top of Tk, and there you could bind to '<KeyPress>' and get called with any key. But I'm not sure how easy it is to interact with the Tk base within a turtle program.
Reply
#3
import string

for letter in string.ascii_letters:
    turtle.onkey(my_func, letter)
bowlofred likes this post
Reply
#4
Many thanks - that's a great way of geneating multiple onkey(). How do I determine which letter was actually pressed?
I meant generating
Reply
#5
You can use functools.partial to add the letter pressed to the called function handler
import functools
import string
import turtle


def key_handler(key):
    print(key)


for letter in string.ascii_letters:
    turtle.onkey(functools.partial(key_handler, letter), letter)

window = turtle.Screen()
window.listen()
window.mainloop()
Reply
#6
(Jun-26-2021, 09:48 AM)Yoriz Wrote: You can use functools.partial to add the letter pressed to the called function handler
import functools
import string
import turtle


def key_handler(key):
    print(key)


for letter in string.ascii_letters:
    turtle.onkey(functools.partial(key_handler, letter), letter)

window = turtle.Screen()
window.listen()
window.mainloop()

Thanks very much for this. I'll investigate how partials work.
Reply
#7
You can also use a lambda expression.
turtle.onkey(lambda arg=letter:key_handler(arg))
Reply
#8
(Jun-27-2021, 02:59 PM)simonc8 Wrote:
(Jun-26-2021, 09:48 AM)Yoriz Wrote: You can use functools.partial to add the letter pressed to the called function handler
import functools
import string
import turtle


def key_handler(key):
    print(key)


for letter in string.ascii_letters:
    turtle.onkey(functools.partial(key_handler, letter), letter)

window = turtle.Screen()
window.listen()
window.mainloop()

Thanks very much for this. I'll investigate how partials work.

This turns out to be more complicated because I'm trying to set this up in trinket, which doesn't have the functools library available... (it only has a limited version of string as well.)

I can put a
lambda: key_handler(letter), letter
function in the onkey expression and it doesn't give an error and I'm now trying to get the key_handler function to generate a unique function for each letter but haven't managed to make it work yet.
Reply
#9
Look at my corrected lambda example. Your version doesn't work because all the lambda's share the same variable, "letter". When the lambda is evaluated it uses the current value of "letter". That is why no matter what key you press, all the lambda's think 'Z' was pressed. In the code below, all lambdas reference the same variable. 'x'.
lambdas = [lambda: print(x) for x in range(5)]
for func in lambdas:
    func()
Output:
4 4 4 4 4
To get a different letter for each lambda you need to do what I did in my corrected example. When you define a lambda like this:
lambdas = [lambda arg=x: print(arg) for x in range(5)]
for func in lambdas:
    func()
Output:
0 1 2 3 4
You get a different value for arg for each lambda. It is like the lambdas are defined with a default first argument. The default value for the argument is the current value of x, not the final value of x.
def func(arg=0):  # Where the default value = current value of x
    print(arg)[/output]
You need to be careful using this trick because it really does work exactly like you are providing a default value. If the function is passed an argument, the argument value is used, not the default value.
lambdas = [lambda arg=x: print(arg) for x in range(5)]
for func in lambdas:
    func(42)
Output:
42 42 42 42 42
Reply
#10
Hi Dean

Many thanks for your very detailed reply. I apologise for missing your ealier post as it got lost up the thread when I was replying to a different post.

I am having trouble getting the code to work in trinket, as the implementation of Python is very incomplete. (We use trinket in our Code Club as it gives everyone access to Python without having to install it on their machines, which has been especially useful in lockdown.)

In trinket
lambdas = [lambda arg=x: print(arg) for x in range(5)]
for func in lambdas:
    func()
produces an output of all 4s, so it's apparently not keeping the lambdas separate and overwriting each previous one. (It works properly in IDLE.)

Is there another way of doing this? I saw code where the called function from a turtle.onclick generated an inner function, but I haven't been able to adapt that to what I need.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  wn = turtle.screen() AttributeError: module 'turtle' has no attribute 'screen' Shadower 1 6,186 Feb-06-2019, 01:25 AM
Last Post: woooee
  t.onkey command isn't working PythonSnake 2 3,057 Jan-24-2019, 08:02 PM
Last Post: PythonSnake
  Help! Turtle not working, even when we click the turtle demo in IDLE nothing happens. BertyBee 3 5,643 Jan-04-2019, 02:44 AM
Last Post: SheeppOSU

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020