Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter getting key pressed event from a function

Tags:

python

tkinter

I have the following code,

If I press 'Left Arrow Key', it only prints move player to left But I need a functionality in which pressing the given arrow key moves the player in the given direction.

Is there a way in which I can detect key press event in my move_dir function
PS: fairly new to python

import Tkinter as tk

move = 1
pos = -1


def move_dir():
    global move
    global pos
    while move ==1:
        if pos == 0:
            print 'move player to left'

        elif pos == 1:
            print 'move player to right'

        elif pos == -1:
            print 'stop moving!'

def kr(event):
    global move
    global pos
    global root
    if event.keysym == 'Right':
        move = 1
        pos = 0
        move_dir()
        print 'right ended'
    elif event.keysym == 'Left':
        move = 1
        pos = 1
        move_dir()
        print 'left ended'
    elif event.keysym == 'Space':
        move = 0
        move_dir()
    elif event.keysym == 'Escape':
        root.destroy()

root = tk.Tk()
print( "Press arrow key (Escape key to exit):" )
root.bind_all('<KeyRelease>', kr)
root.mainloop()
like image 382
Vabs Avatar asked Aug 21 '26 09:08

Vabs


1 Answers

If you're wanting to animate something, you should use after to set up an animation loop. An animation loop looks like this:

def animate():
    <draw one frame of your animation>
    after(<delay>, animate)

You can put whatever code you want to draw a frame. In your case it sounds like you want to move something left or right. The <delay> parameter defines your frame rate. For example, to get 30FPS your delay would be about 33 (1000ms / 30). The only important thing to be aware of is that <draw one from of your animation> needs to run pretty quickly (10's of milliseconds or less) in order to not block the GUI.

For your particular problem, you can set a variable to define the direction when the user presses a key, then unset the variable when they release the key. Your event handler and animate function might look something like this:

def animate():
    if direction is not None:
        print "move player to the ", direction
    after(33, animate)

def on_keypress(event):
    global direction
    if event.keysym == "Left":
        direction = "left"
    elif event.keysum == "right":
        direction = "right"

def on_keyrelease(event):
    global direction
    direction = None

See how that works? When you press a key it defines the direction. Then, every 33 milliseconds you check for the direction, and move your player if the direction is defined. When the user releases the button, the direction becomes undefined and the movement stops.

Putting it all together, and using a class to avoid using global variables, it looks something like the following. This creates a ball on a canvas which you can move left, right, up and down:

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.direction = None

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)
        self.canvas.create_oval(190, 190, 210, 210, 
                                tags=("ball",),
                                outline="red", fill="red")

        self.canvas.bind("<Any-KeyPress>", self.on_press)
        self.canvas.bind("<Any-KeyRelease>", self.on_release)
        self.canvas.bind("<1>", lambda event: self.canvas.focus_set())

        self.animate()

    def on_press(self, event):
        delta = {
            "Right": (1,0),
            "Left": (-1, 0),
            "Up": (0,-1),
            "Down": (0,1)
        }
        self.direction = delta.get(event.keysym, None)

    def on_release(self, event):
        self.direction = None

    def animate(self):
        if self.direction is not None:
            self.canvas.move("ball", *self.direction)
        self.after(50, self.animate)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
like image 191
Bryan Oakley Avatar answered Aug 22 '26 22:08

Bryan Oakley