import tkinter as tk from dataclasses import dataclass import ttkbootstrap as ttk from PIL import Image, ImageTk from ttkbootstrap.scrolled import ScrolledFrame class Slide(tk.Frame): def __init__(self, preview, image: Image.Image): super().__init__(preview._frame) self.preview = preview self.image = image self.imagetk = ImageTk.PhotoImage(image) self.label = tk.Label(self, image=self.imagetk, borderwidth=1, relief=tk.SOLID) self.label.pack(fill=tk.X, pady=(0, 5)) self.delbutton = ttk.Button(self, text="Löschen", bootstyle="danger-outline", command=self._on_delete) self.delbutton.pack(fill=tk.X) self._is_selected = False self.highlight = None self._configure_id = None self.bind("", self._on_resize) self.label.bind("", self._on_select) def _on_resize(self, e: tk.Event): if self._configure_id != None: self.after_cancel(self._configure_id) self._configure_id = self.after(100, self._on_final_resize) def _on_select(self, e: tk.Event): if self._is_selected: self._on_unselect() else: self._is_selected = True self.highlight = tk.Label(self, text="Ausgewählt", bg="green") self.highlight.place(x=0, y=0) self.preview.notify_selection(self) def _on_unselect(self): self._is_selected = False if self.highlight is not None: self.highlight.destroy() def _on_final_resize(self): thumbnail = self.image.copy() thumbnail.thumbnail(size=(self.winfo_width(), self.image.height), resample=Image.NEAREST) self.imagetk = ImageTk.PhotoImage(thumbnail) self.label.configure(image=self.imagetk) self._configure_id = None def _on_delete(self): self.preview.remove(self) class SlidePreview(ScrolledFrame): def __init__(self, parent, *args, columns: int = 4, **kwargs): super().__init__(parent, *args, **kwargs) self._frame = tk.Frame(self) self._frame.pack(fill=tk.BOTH, expand=True) self.columns = columns for column in range(columns): self._frame.grid_columnconfigure(column, weight=1) self._selected_index = -1 self._slides = [] def _on_resize(self, e: tk.Event): slide = self._slides[0] slide.grid_forget() slide.grid(row=0, column=0, sticky=tk.EW) def notify_selection(self, selected: Slide): self._selected_index = self._slides.index(selected) for slide in self._slides: if slide is not selected: slide._on_unselect() def notify_unselected(self, unselected: Slide): if self._slides.index(unselected) == self._selected_index: self._selected_index = -1 def add(self, slide: Image.Image): index = len(self._slides) s = Slide(self, slide) s.grid(row=index // self.columns, column=index % self.columns, sticky=tk.NSEW, padx=10, pady=10) self._slides.append(s) def insert(self, slide: Image.Image, index: int): s = Slide(self, slide) self._slides.insert(index, s) for index, slide in enumerate(self._slides): slide.grid_forget() slide.grid(row=index // self.columns, column=index % self.columns, sticky=tk.NSEW, padx=10, pady=10) slide._on_final_resize() if index <= self._selected_index: self._selected_index += 1 def remove(self, slide: Slide): index = self._slides.index(slide) if index < 0: return if index == self._selected_index: self._selected_index = -1 elif index < self._selected_index: self._selected_index -= 1 slide.destroy() del self._slides[index] for index, slide in enumerate(self._slides[index:], start=index): slide.grid_forget() slide.grid(row=index // self.columns, column=index % self.columns, sticky=tk.NSEW, padx=10, pady=10) def clear(self): for slide in self._slides: slide.destroy() self._slides = [] self._selected_index = -1 def __len__(self): return len(self._slides) def get_images(self) -> list[Image.Image]: return [slide.image for slide in self._slides] if __name__ == "__main__": main = tk.Tk() main.geometry("800x400") sp = SlidePreview(main) sp.pack(fill=tk.BOTH, expand=True) for filename in [f"{i:02}" for i in range(16)]: img = Image.open(f"machine learning in der radiologie_5ebbrbz/{filename}.png") sp.add(img) main.mainloop()