Alexis Randell
Alexis Randell

Reputation: 31

Key bindings don't work when using askopenfilename dialog in tkinter

I'm working on a simple app for reading and displaying sequences of image files from within a zip file using python 3.4 with tkinter, like you might use for reading .cbz comic book files. Ideally I'd like to bind the left and right keys to show the last and next images respectively. This works fine if I specify the name of the zip file in the code; however, if I use filedialog.askopenfilename() dialogue box to specify the file, then the keyboard key bindings no longer work.

I assumed this was due to a focus issue, and I've tried setting the focus to the label to which the keys are bound (both using the label.focus_set() method and the parent option of the askopenfilename() dialogue) without success.

Code is below. Any help on this would be greatly appreciated, as it's starting to drive me nuts.

from tkinter import *
from tkinter import filedialog
import io
from PIL import Image, ImageTk
import zipfile

class ComicDisplay():
    def __init__(self, master):
        frame = Frame(master)
        frame.pack(fill='both', expand=1)
        self.parent = master
        self.fname = ""
        self.label = Label(frame, bg="brown", height=500)
        self.current_zip_file = filedialog.askopenfilename(filetypes=[(zip, "*.zip")])
        # self.current_zip_file = "C:\\Users\\Alexis\\Dropbox\\Photos.zip"
        self.image_list = self.acquire_image_list(self.current_zip_file)
        self.current_image_number = 0
        self.pil_image = self.acquire_image(self.current_zip_file, self.image_list[self.current_image_number])
        self.tk_image = ImageTk.PhotoImage(self.pil_image)
        self.parent.title(self.fname)

        self.label.configure(image=self.tk_image)
        self.label.focus_set()
        self.label.bind("<Configure>", self.image_resizing)
        self.label.bind("<Left>", self.get_last_image)
        self.label.bind("<Right>", self.get_next_image)
        self.label.bind("<Button-1>", self.get_next_image)
        self.label.pack(padx=5, pady=5, fill='both', expand=1)

    def acquire_image_list(self, zip_file):
        image_list = []
        with zipfile.ZipFile(zip_file, "r") as myFile:
            for filename in myFile.namelist():
                image_list.append(filename)
        image_list.sort()
        return image_list

    def acquire_image(self, zip_file, image_file):
        with zipfile.ZipFile(zip_file, "r") as myFile:
            self.fname = image_file
            image_bytes = myFile.read(image_file)
            data_stream = io.BytesIO(image_bytes)
            pil_image = Image.open(data_stream)
            pil_image = self.image_sizer(pil_image)
            return pil_image

    def image_sizer(self, image_file, window_size=500):
        w, h = image_file.size
        if w > h:
            image_file_height = int(h*(window_size/w))
            image_file = image_file.resize((window_size, image_file_height), Image.ANTIALIAS)
        else:
            image_file_width = int(w*(window_size/h))
            image_file = image_file.resize((image_file_width, window_size), Image.ANTIALIAS)
        return image_file

    def image_resizing(self, event):
        new_height = root.winfo_height() - 14
        new_size_image = self.image_sizer(self.pil_image, new_height)
        self.tk_image = ImageTk.PhotoImage(new_size_image)
        self.label.configure(image=self.tk_image)

    def get_next_image(self, event):
        if self.current_image_number >= len(self.image_list)-1:
            self.current_image_number = 0
        else:
            self.current_image_number += 1
        self.update_image()

    def get_last_image(self, event):
        if self.current_image_number == 0:
            self.current_image_number = len(self.image_list)-1
        else:
            self.current_image_number -= 1
        self.update_image()

    def update_image(self):
        self.fname = self.image_list[self.current_image_number]
        self.pil_image = self.acquire_image(self.current_zip_file, self.image_list[self.current_image_number])
        self.tk_image = ImageTk.PhotoImage(self.pil_image)
        self.parent.title(self.fname)
        self.image_resizing(None)




root = Tk()
app = ComicDisplay(root)
root.mainloop()

Upvotes: 1

Views: 516

Answers (2)

golden96371
golden96371

Reputation: 410

If you call root.update() before and after askopenfilename(), the key bindings work.

Upvotes: 0

Alexis Randell
Alexis Randell

Reputation: 31

Bryan's comment held the answer: delaying the open file dialogue until after the window was initialized solved the problem. Instead of opening the file when the app starts, creating a file open method allows the key bindings to work as they should.

Upvotes: 2

Related Questions