import tkinter as tk from tkinter import filedialog from PIL import Image, ImageTk import json import base64 import io import re from artist_dictionary import artist_dict class ArtistThumbnailViewer: def __init__(self, master): self.master = master self.master.title("NAIA/WEBUIA 대체용 작가명 태그 미리보기 뷰어, Ctrl+C로 작가명 복사 가능") self.master.geometry("728x525") self.artist_data = {} self.artist_list = [] self.last_search = "" self.left_frame = tk.Frame(master, width=300) self.left_frame.pack(side=tk.LEFT, fill=tk.Y) self.right_frame = tk.Frame(master) self.right_frame.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH) self.search_entry = tk.Entry(self.left_frame, font=("Malgun Gothic", 12)) self.search_entry.pack(pady=5) self.search_entry.bind('', self.popup_search) self.search_entry.bind('', lambda e: self.popup.withdraw()) self.listbox_frame = tk.Frame(self.left_frame) self.listbox_frame.pack(pady=5, fill=tk.BOTH, expand=True) self.scrollbar = tk.Scrollbar(self.listbox_frame) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.listbox = tk.Listbox(self.listbox_frame, font=("Malgun Gothic", 12), width=20, height=30, yscrollcommand=self.scrollbar.set) self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.scrollbar.config(command=self.listbox.yview) self.listbox.pack(pady=5) self.listbox.bind('<>', self.display_image) self.canvas = tk.Canvas(self.right_frame, bg="white") self.canvas.pack(expand=True, fill=tk.BOTH) self.menu = tk.Menu(master) self.menu.add_command(label="artist_thumbnail 파일 불러오기", command=self.load_json_file) master.config(menu=self.menu) # Popup listbox for search self.popup = tk.Toplevel(master) self.popup.withdraw() self.popup.overrideredirect(True) self.plistbox = tk.Listbox(self.popup, font=("Malgun Gothic", 12), width=40, height=11, borderwidth=2, highlightbackground='lightgrey') self.plistbox.pack() self.plistbox.bind('<>', self.select_popup_result) def load_json_file(self): filepath = filedialog.askopenfilename(filetypes=[("All", "artist_thumb*")]) if not filepath: return with open(filepath, 'r', encoding='utf-8') as file: self.artist_data = json.load(file) self.artist_list = sorted( [key for key in self.artist_data if key in artist_dict], key=lambda k: artist_dict[k], reverse=True ) self.update_listbox(self.artist_list) def update_listbox(self, items): self.listbox.delete(0, tk.END) for item in items: self.listbox.insert(tk.END, item) def display_image(self, event=None): try: selected = self.listbox.get(self.listbox.curselection()) except: return img_data = self.artist_data.get(selected, [None])[0] if img_data: img_bytes = base64.b64decode(img_data) image = Image.open(io.BytesIO(img_bytes)) image = image.resize((512, 512), Image.LANCZOS) self.tk_image = ImageTk.PhotoImage(image) self.canvas.delete("all") self.canvas.create_image(10, 10, anchor='nw', image=self.tk_image) else: self.canvas.delete("all") def popup_search(self, event=None): search_text = self.search_entry.get().strip().lower() self.plistbox.delete(0, tk.END) results = [] for artist in self.artist_list: if search_text in artist.lower(): value = artist_dict.get(artist, 0) results.append((artist, value)) results.sort(key=lambda x: x[1], reverse=True) results = results[:40] if results: for k, v in results: v_formatted = f"{v:>9}".replace(' ', ' ') formatted_line = f"{v_formatted} {k}" self.plistbox.insert(tk.END, formatted_line) abs_x = self.search_entry.winfo_rootx() abs_y = self.search_entry.winfo_rooty() + 30 self.popup.geometry(f"+{abs_x}+{abs_y}") self.popup.deiconify() else: self.popup.withdraw() def select_popup_result(self, event=None): try: selection = self.plistbox.get(self.plistbox.curselection()) keyword = re.sub(r'^\s*\d+\s+', '', selection.strip().split(maxsplit=1)[-1]) index = self.artist_list.index(keyword) self.popup.withdraw() self.listbox.select_clear(0, tk.END) self.listbox.select_set(index) self.listbox.see(index) self.display_image() except: pass if __name__ == "__main__": root = tk.Tk() app = ArtistThumbnailViewer(root) root.mainloop()