152 lines
4.8 KiB
Python
Executable File
152 lines
4.8 KiB
Python
Executable File
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("<Configure>", self._on_resize)
|
|
self.label.bind("<Button-1>", 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()
|