Home > Software engineering >  I can't bind the arrow key events
I can't bind the arrow key events

Time:11-28

I currently have a next slice and previous slice button that can be clicked to move through the images. I would also like the keyboard left and right arrows to allow the user to go through the previous and next slices. So there should be two ways to go through the images. I am unable to get the keyboard click work within prev_image and next_image.

import tkinter as tk

class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)  # python3 style
    
        self.master.title("Slideshow")

        top_frame = tk.Frame(self)
        top_frame.pack()
    
        image_frame = tk.Frame(self)
        image_frame.pack()

        previous_button = tk.Button(top_frame, text="Previous Slice", command=self.prev_image)
        previous_button.pack(side="left")

        next_button = tk.Button(top_frame, text="  Next Slice  ", command=self.next_image)
        next_button.pack(side="left")

        self.canvas = tk.Canvas(image_frame, bg='red')
        self.canvas.pack()
    
        self.canvas.bind('<Left>', self.prev_image)
        self.canvas.bind('<Right>', self.next_image)
        self.canvas.focus_set()

        self.master.bind('<Left>', self.prev_image)
        self.master.bind('<Right>', self.next_image)
    
    def prev_image(self, event=None):
        print('prev_image')
        if event:
            print('even:', event)

    def next_image(self, event=None):
        print('next_image')
        if event:
            print('even:', event)

root = tk.Tk()
app = App(root)
app.pack()
root.mainloop()

 

Image:

enter image description here

CodePudding user response:

You have to set focus on canvas to get keys in canvas

        self.canvas.bind('<Left>', self.prev_image)
        self.canvas.bind('<Right>', self.next_image)
        self.canvas.focus_set()

or you may bind keys to master window

        self.master.bind('<Left>', self.prev_image)
        self.master.bind('<Right>', self.next_image)

Second version may be better because canvas may lose focus - ie. when you use key tab to jump from widget to widget.


Other problem.

command= needs function which doesn't get arguments but bind() needs function which get one argument - because it sends information about event (ie. pressed key, mouse position, etc.)

To use the same function in command= and bind() you need argument with default value - ie. even=None

    def prev_image(self, event=None):
        # ... code ...

    def next_image(self, event=None):
        # ... code ...

Minimal working example:

import tkinter as tk

class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)  # python3 style
        
        self.master.title("Slideshow")

        top_frame = tk.Frame(self)
        top_frame.pack()
        
        image_frame = tk.Frame(self)
        image_frame.pack()
    
        previous_button = tk.Button(top_frame, text="Previous Slice", command=self.prev_image)
        previous_button.pack(side="left")

        next_button = tk.Button(top_frame, text="  Next Slice  ", command=self.next_image)
        next_button.pack(side="left")

        self.canvas = tk.Canvas(image_frame, bg='red')
        self.canvas.pack()
        
        #self.canvas.bind('<Left>', self.prev_image)
        #self.canvas.bind('<Right>', self.next_image)
        #self.canvas.focus_set()

        self.master.bind('<Left>', self.prev_image)
        self.master.bind('<Right>', self.next_image)
        
    def prev_image(self, event=None):
        print('prev_image')
        self.canvas['bg'] = 'blue'
        if event:
            print('even:', event)

    def next_image(self, event=None):
        print('next_image')
        self.canvas['bg'] = 'green'
        if event:
            print('even:', event)


if __name__ == "__main__":
    app = App()
    app.pack()
    app.mainloop()
    
    #root = tk.Tk()
    #app = App(root)
    #app.pack()
    #root.mainloop()
  • Related