0

I have been working on making an etch-a-sketch like program where you can use the arrow keys to draw. I have noticed that I cannot hold two keys down to go across the screen like the up and left arrow key. Is this possible and how can I do it?

Here is my code so far:

import tkinter as tk
import turtle

def k1(event):
    t.forward(1)

def k2(event):
    t.left(1)

def k3(event):
    t.right(1)

def k4(event):
    t.back(1)

window = tk.Tk()

window.geometry("750x500")
window.resizable(False, False)

canvas = tk.Canvas(master=window, width=500, height=500, bg="white")
canvas.pack()

t = turtle.RawTurtle(canvas)

window.bind("<Up>", k1)
window.bind("<Left>", k2)
window.bind("<Right>", k3)
window.bind("<Down>", k4)

window.mainloop()
not here
  • 43
  • 1
  • 5
  • I do not understand your problem. When I press the left or right arrow the on screen arrow rotates then I press forward and it goes in that direction. It works in all directions so what do you mean about "across the screen"? It goes across the screen in any direction for me. Unless you are wanting it to move forward while also turning then you should clarify that in your question. – Mike - SMT Jan 28 '20 at 14:15
  • I mean so you can hold the up and left at the same time so it goes in a \ direction rather than keep switching between up and left keys. – not here Jan 28 '20 at 14:26
  • If that is the case check out this post. https://stackoverflow.com/a/44086242/7475225 . The normal binding alone cannot do what you want. But with some added functionality you can get there. – Mike - SMT Jan 28 '20 at 14:29

1 Answers1

1

By combining the method employed by Josselin on this post Press 2 keys at once to move diagonally tkinter? with your turtle we can capture when multiple keys are pressed and what to do about that.

This code allows you to press multiple keys at once to get at least a rotating motion.

import tkinter as tk
import turtle


window = tk.Tk()
window.geometry("750x500")
window.resizable(False, False)
pressedStatus = {"Up": False, "Down": False, "Left": False, "Right": False}
canvas = tk.Canvas(master=window, width=500, height=500, bg="white")
canvas.pack()

t = turtle.RawTurtle(canvas)

def pressed(event):
    pressedStatus[event.keysym] = True

def released(event):
    pressedStatus[event.keysym] = False

def set_bindings():
    for char in ["Up", "Down", "Left", "Right"]:
        window.bind("<KeyPress-%s>" % char, pressed)
        window.bind("<KeyRelease-%s>" % char, released)

def animate():
    if pressedStatus["Up"]: t.forward(1)
    if pressedStatus["Down"]: t.back(1)
    if pressedStatus["Left"]: t.left(1)
    if pressedStatus["Right"]: t.right(1)
    canvas.update()
    window.after(10, animate)

set_bindings()
animate()
window.mainloop()

With a little bit more work and another dictionary to track the rotation we can get diagonal lines at any degree you want. I am assuming 45 degrees is the goal so try the below out.

import tkinter as tk
import turtle


window = tk.Tk()
window.geometry("750x500")
window.resizable(False, False)
pressed_status = {"Up": False, "Down": False, "Left": False, "Right": False}
rotation_lock = {"Left": False, "Right": False}  # use to lock the rotation event so we cont constantly rotate.
canvas = tk.Canvas(master=window, width=500, height=500, bg="white")
canvas.pack()

t = turtle.RawTurtle(canvas)

def pressed(event):
    pressed_status[event.keysym] = True

def released(event):
    pressed_status[event.keysym] = False
    if event.keysym == 'Left' or event.keysym == 'Right':
        rotation_lock[event.keysym] = False

def set_bindings():
    for char in ["Up", "Down", "Left", "Right"]:
        window.bind("<KeyPress-%s>" % char, pressed)
        window.bind("<KeyRelease-%s>" % char, released)

def animate():
    # By first checking if 2 keys are pressed we can make sure we get the rotation we are looking for.
    # Then if not 2 keys then process single keys.
    # We also want to lock the rotation after our first rotation as to not constantly turn at a 45 degree angle.
    if pressed_status["Up"] and pressed_status["Left"]:
        t.forward(1)
        if not rotation_lock['Left']:
            rotation_lock['Left'] = True
            t.left(45)
    elif pressed_status["Up"] and pressed_status["Right"]:
        t.forward(1)
        t.right(1)
        if not rotation_lock['Right']:
            rotation_lock['Right'] = True
            t.right(45)
    elif pressed_status["Down"] and pressed_status["Left"]:
        t.back(1)
        if not rotation_lock['Left']:
            rotation_lock['Left'] = True
            t.left(45)
    elif pressed_status["Down"] and pressed_status["Right"]:
        t.back(1)
        if not rotation_lock['Right']:
            rotation_lock['Right'] = True
            t.right(45)

    elif pressed_status["Up"]: t.forward(1)
    elif pressed_status["Down"]: t.back(1)
    elif pressed_status["Left"]: t.left(1)
    elif pressed_status["Right"]: t.right(1)
    canvas.update()
    window.after(40, animate)

set_bindings()
animate()
window.mainloop()

If we add a 3rd key to the mix we can chose to switch between diagonal and curved lines.

Take a look at this example:

import tkinter as tk
import turtle


window = tk.Tk()
window.geometry("750x500")
window.resizable(False, False)
pressed_status = {"Up": False, "Down": False, "Left": False, "Right": False, "Control_L": False}
rotation_lock = {"Left": False, "Right": False}  # use to lock the rotation event so we cont constantly rotate.
canvas = tk.Canvas(master=window, width=500, height=500, bg="white")
canvas.pack()

t = turtle.RawTurtle(canvas)

def pressed(event):
    pressed_status[event.keysym] = True

def released(event):
    pressed_status[event.keysym] = False
    if event.keysym == 'Left' or event.keysym == 'Right':
        rotation_lock[event.keysym] = False

def set_bindings():
    for char in ["Up", "Down", "Left", "Right", "Control_L"]:
        window.bind("<KeyPress-%s>" % char, pressed)
        window.bind("<KeyRelease-%s>" % char, released)

def animate():
    # By first checking if 2 keys are pressed we can make sure we get the rotation we are looking for.
    # Then if not 2 keys then process single keys.
    # We also want to lock the rotation after our first rotation as to not constantly turn at a 45 degree angle.
    if pressed_status["Up"] and pressed_status["Left"]:
        t.forward(1)
        if pressed_status["Control_L"]:
            t.left(1)
        else:
            if not rotation_lock['Left']:
                rotation_lock['Left'] = True
                t.left(45)
    elif pressed_status["Up"] and pressed_status["Right"]:
        t.forward(1)
        if pressed_status["Control_L"]:
            t.right(1)
        else:
            if not rotation_lock['Right']:
                rotation_lock['Right'] = True
                t.right(45)
    elif pressed_status["Down"] and pressed_status["Left"]:
        t.back(1)
        if pressed_status["Control_L"]:
            t.left(1)
        else:
            if not rotation_lock['Left']:
                rotation_lock['Left'] = True
                t.left(45)
    elif pressed_status["Down"] and pressed_status["Right"]:
        t.back(1)
        if pressed_status["Control_L"]:
            t.right(1)
        else:
            if not rotation_lock['Right']:
                rotation_lock['Right'] = True
                t.right(45)

    elif pressed_status["Up"]: t.forward(1)
    elif pressed_status["Down"]: t.back(1)
    elif pressed_status["Left"]: t.left(1)
    elif pressed_status["Right"]: t.right(1)
    canvas.update()
    window.after(40, animate)

set_bindings()
animate()
window.mainloop()

enter image description here

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79