Próbuję zbudować przeglądarkę obrazu, która ładuje obrazy z folderu. Powinien mieć przyciski do przodu / do tyłu i zakończenia. Wydaje się, że działa dobrze z jednym problemem:

Więc właśnie robię ścieżki obrazu z tym:

def get_files_from_folder(path, allowed_extensions):
    found_paths = []

    for (dir_path, _, file_names) in os.walk(path):
        for file_name in file_names:
            for allowed_extension in allowed_extensions:
                if file_name.lower().endswith(allowed_extension.lower()):
                    found_paths.append(os.path.join(dir_path, file_name))

                    break

    return found_paths

Mam GUI TKININ dla przeglądarki obrazu:

class UI:
    def __init__(self, icon_path, images_folder_path):
        self.current_index = 0
        self.root = tk.Tk()
        self.root.title('Images')
        self.root.iconbitmap(icon_path)

        self.button_quit = tk.Button(self.root, text = 'Quit', padx = 60, command = self.root.quit)
        self.button_forward = tk.Button(self.root, text = '>>', command = self.forward)
        self.button_backward = tk.Button(self.root, text = '<<', command = self.backward)

        self.button_quit.grid(row = 1, column = 1)
        self.button_forward.grid(row = 1, column = 2)
        self.button_backward.grid(row = 1, column = 0)

        self.images_paths = get_files_from_folder(images_folder_path, ['.jpg', '.png'])
        self.tk_images = []
        print(get_files_from_folder)
        for image_path in self.images_paths:
            self.tk_images.append(ImageTk.PhotoImage(Image.open(image_path)))

        self.current_image = tk.Label(image = self.tk_images[0])
        self.current_image.grid(column = 0, row = 0, columnspan = 3)

        self.root.mainloop()

I z jakiegoś powodu, tutaj, gdy używam tk.DISABLED, po prostu go nie wyłączy

    def backward(self):

        if self.current_index == 0:
            self.button_backward = self.button_backward = tk.Button(self.root, text = '<<', command = self.backward, state = tk.DISABLED)

        self.current_image.grid_forget()

        self.current_index -= 1
        self.current_image = tk.Label(image = self.tk_images[self.current_index])
        self.current_image.grid(column = 0, row = 0, columnspan = 3)

Tak samo dla przodu:

    def forward(self):

        self.current_image.grid_forget()

        if self.current_index == len(self.tk_images)-1:
            self.button_forward = self.button_forward = tk.Button(self.root, text = '>>', command = self.forward, state = tk.DISABLED)
        else:
            self.button_forward.state = tk.ACTIVE
        self.current_index += 1
        self.current_image = tk.Label(image = self.tk_images[self.current_index])
        self.current_image.grid(column = 0, row = 0, columnspan = 3)
0
Zselter 20 marzec 2020, 01:47

1 odpowiedź

Najlepsza odpowiedź

Jest co najmniej kilka rzeczy nie tak z bieżącym kodem dotyczącym poleceń do przodu i do tyłu Button s. Jeśli chodzi o wyłączenie Button s, które można wykonać, wywołanie metody config() - nie , tworząc nowy lub przypisywanie nowej wartości do istniejących {{x3 }} Atrybut (tj. {x4}}).

Podobnie nie jest dobrą praktyką, aby stale tworzyć widżety {x0}} za każdym razem, gdy jest naciśnięty jeden z przycisków, a obraz na niej zmienia się. Lepiej zmienić opcję image= istniejące {x2}}. Robiąc to również często upraszcza, co należy zrobić.

Ponadto logika do mocowania self.current_index była wadna i pozwoliłaby na wyjść poza zasięg, a IndexError s miała wystąpić. Jest to bardziej skomplikowane niż przewidywałem, ale myślę, że pomyślałem dobry sposób na radzenie sobie z nim, a mianowicie, umieszczając całą logikę prywatną metodę _change_current_index() i wywołanie go z funkcji wywołania zwrotnego do przodu i do tyłu.

Wreszcie, Użytkownik @ ACW1668 skomentował, że ładuje wszystkie obrazy w pamięci na początku programu może być dwa powoli. Aby tego uniknąć, zastąpiłem listę wszystkich załadowanych obrazów, które miałeś (self.tk_images) z połączeniami do innej nowej metody prywatnej o nazwie _open_image(), które podtrzymywały swoje wyniki, mając functools.lru_cache Decorator do tego. To sprawia, że metoda pamięta, jakie wartości zwracały już o ograniczoną liczbę indeksów, ograniczając liczbę ich w pamięci w dowolnym momencie.

Uwaga Ponownie sformatowałem również kod, aby lepiej być zgodny z PEP 8 - Przewodnik po stylu dla kodu Python wytyczne, aby były bardziej czytelne.

from functools import lru_cache
import tkinter as tk
import os
from PIL import Image, ImageTk


class UI:
    IMG_CACHE_SIZE = 10

    def __init__(self, icon_path, images_folder_path):
        self.current_index = 0
        self.root = tk.Tk()
        self.root.title('Images')
#        self.root.iconbitmap(icon_path)

        self.button_quit = tk.Button(self.root, text='Quit', padx=60, command=self.root.quit)
        self.button_forward = tk.Button(self.root, text='>>', command=self.forward)
        self.button_backward = tk.Button(self.root, text='<<', command=self.backward)

        self.button_quit.grid(row=1, column=1)
        self.button_forward.grid(row=1, column=2)
        self.button_backward.grid(row=1, column=0)

        self.image_paths = get_files_from_folder(images_folder_path, ['.jpg', '.png'])
        self.current_image = tk.Label(image=self._open_image(0))
        self.current_image.grid(column=0, row=0, columnspan=3)

        self._change_current_index()  # Initializes fwd and bkd button states.
        self.root.mainloop()

    @lru_cache(maxsize=IMG_CACHE_SIZE)
    def _open_image(self, i):
        image_path = self.image_paths[i]
        return ImageTk.PhotoImage(Image.open(image_path))

    def backward(self):
        self._change_current_index(-1)

    def forward(self):
        self._change_current_index(1)

    def _change_current_index(self, delta=0):
        self.current_index += delta

        # Update state of forward and backward buttons based on new index value.
        bkd_state = (tk.DISABLED if self.current_index == 0 else tk.ACTIVE)
        self.button_backward.config(state=bkd_state)
        fwd_state = (tk.DISABLED if self.current_index == len(self.image_paths)-1 else tk.ACTIVE)
        self.button_forward.config(state=fwd_state)

        # Update image on Label.
        self.current_image.config(image=self._open_image(self.current_index))


def get_files_from_folder(path, allowed_extensions):
    found_paths = []
    for (dir_path, _, file_names) in os.walk(path):
        for file_name in file_names:
            for allowed_extension in allowed_extensions:
                if file_name.lower().endswith(allowed_extension.lower()):
                    found_paths.append(os.path.join(dir_path, file_name))
                    break
    return found_paths

if __name__ == '__main__':
    UI('.', './images_test')

0
martineau 22 marzec 2020, 16:15