image_browser.py
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import configparser
# pip install Pillow
class ImageBrowser:def __init__(self, root):self.root = rootself.root.title("图片浏览器")# 配置文件路径self.config_file = "image_browser_config.ini"# 图片列表和当前索引self.image_list = []self.current_index = 0self.current_image_path = Noneself.current_directory = ""# 创建界面self.create_widgets()# 绑定快捷键self.root.bind('<Left>', lambda e: self.previous_image())self.root.bind('<Right>', lambda e: self.next_image())self.root.bind('<Delete>', lambda e: self.delete_image())# 加载上次的状态self.load_config()# 如果有保存的目录,自动加载if self.current_directory:self.dir_entry.delete(0, tk.END)self.dir_entry.insert(0, self.current_directory)self.load_images()else:# 默认设置为当前目录current_dir = os.getcwd()self.dir_entry.insert(0, current_dir)def create_widgets(self):# 目录选择区域dir_frame = tk.Frame(self.root)dir_frame.pack(pady=10, padx=10, fill=tk.X)self.dir_entry = tk.Entry(dir_frame, width=50)self.dir_entry.pack(side=tk.LEFT, padx=5)browse_btn = tk.Button(dir_frame, text="浏览目录", command=self.browse_directory)browse_btn.pack(side=tk.LEFT, padx=5)load_btn = tk.Button(dir_frame, text="加载图片", command=self.load_images)load_btn.pack(side=tk.LEFT, padx=5)# 图片显示区域self.image_label = tk.Label(self.root, text="请选择目录并加载图片", bg="gray", width=100, height=45)self.image_label.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)# 按钮区域btn_frame = tk.Frame(self.root)btn_frame.pack(pady=10)prev_btn = tk.Button(btn_frame, text="上一张 (←)", command=self.previous_image)prev_btn.pack(side=tk.LEFT, padx=10)next_btn = tk.Button(btn_frame, text="下一张 (→)", command=self.next_image)next_btn.pack(side=tk.LEFT, padx=10)delete_btn = tk.Button(btn_frame, text="删除 (Delete)", command=self.delete_image, bg="#ff6b6b")delete_btn.pack(side=tk.LEFT, padx=10)# 状态栏self.status_label = tk.Label(self.root, text="", relief=tk.SUNKEN, anchor=tk.W)self.status_label.pack(side=tk.BOTTOM, fill=tk.X)def browse_directory(self):directory = filedialog.askdirectory()if directory:self.dir_entry.delete(0, tk.END)self.dir_entry.insert(0, directory)def load_config(self):"""从配置文件加载上次的状态"""try:if os.path.exists(self.config_file):config = configparser.ConfigParser()config.read(self.config_file, encoding='utf-8')if 'Settings' in config:self.current_directory = config['Settings'].get('directory', '')saved_index = config['Settings'].get('index', '0')self.current_index = int(saved_index)except Exception as e:print(f"加载配置文件失败: {e}")def save_config(self):"""保存当前状态到配置文件"""try:config = configparser.ConfigParser()config['Settings'] = {'directory': self.current_directory,'index': str(self.current_index)}with open(self.config_file, 'w', encoding='utf-8') as f:config.write(f)except Exception as e:print(f"保存配置文件失败: {e}")def load_images(self):directory = self.dir_entry.get().strip()if not directory:messagebox.showwarning("警告", "请输入或选择目录")returnif not os.path.isdir(directory):messagebox.showerror("错误", "目录不存在")return# 保存当前目录self.current_directory = directory# 支持的图片格式image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff'}self.image_list = []for filename in os.listdir(directory):file_ext = os.path.splitext(filename)[1].lower() # 获取扩展名并转为小写if file_ext in image_extensions:full_path = os.path.join(directory, filename)self.image_list.append(full_path)if not self.image_list:messagebox.showinfo("提示", "该目录下没有找到图片")return# 排序self.image_list.sort()# 验证索引是否有效if self.current_index >= len(self.image_list):self.current_index = 0# 显示图片self.display_image()self.update_status()self.save_config()def display_image(self):if not self.image_list:self.image_label.config(image='', text="没有图片")return# 确保索引在有效范围内if self.current_index >= len(self.image_list):self.current_index = len(self.image_list) - 1if self.current_index < 0:self.current_index = 0# 尝试读取图片,如果失败则跳过到下一张max_attempts = len(self.image_list)attempts = 0pil_img = Nonewhile attempts < max_attempts:self.current_image_path = self.image_list[self.current_index]# 使用PIL读取图片try:pil_img = Image.open(self.current_image_path)breakexcept Exception as e:# 无法读取图片,跳过print(f"无法读取图片: {self.current_image_path}, 错误: {e}")attempts += 1# 移动到下一张self.current_index += 1if self.current_index >= len(self.image_list):self.current_index = 0if attempts >= max_attempts or pil_img is None:messagebox.showerror("错误", "无法读取任何图片")self.image_label.config(image='', text="无法读取图片")return# 转换为RGB模式(如果需要)if pil_img.mode != 'RGB':pil_img = pil_img.convert('RGB')# 调整图片大小以适应窗口w, h = pil_img.sizemax_width = 1100max_height = 750if w > max_width or h > max_height:scale = min(max_width / w, max_height / h)new_w = int(w * scale)new_h = int(h * scale)pil_img = pil_img.resize((new_w, new_h), Image.LANCZOS)# 创建PhotoImagephoto = ImageTk.PhotoImage(pil_img)# 显示图片self.image_label.config(image=photo, text="")self.image_label.image = photo# 更新窗口标题self.root.title(f"图片浏览器 - {os.path.basename(self.current_image_path)} ({self.current_index + 1}/{len(self.image_list)})")# 保存配置self.save_config()def previous_image(self):if not self.image_list:returnself.current_index -= 1if self.current_index < 0:self.current_index = 0self.root.title(f"图片浏览器 - {os.path.basename(self.current_image_path)} ({self.current_index + 1}/{len(self.image_list)})")messagebox.showinfo("提示", "已经是第一张图片")returnself.display_image()self.update_status()def next_image(self):if not self.image_list:returnself.current_index += 1if self.current_index >= len(self.image_list):self.current_index = 0 # 循环到第一张self.root.title(f"图片浏览器 - {os.path.basename(self.current_image_path)} ({self.current_index + 1}/{len(self.image_list)})")messagebox.showinfo("提示", "已回到第一张图片")returnself.display_image()self.update_status()def delete_image(self):if not self.image_list:returnif not self.current_image_path:returntry:os.remove(self.current_image_path)self.image_list.pop(self.current_index)# 删除后保持当前索引不变,会自动指向下一张# 如果删除的是最后一张,索引会自动调整if self.current_index >= len(self.image_list) and len(self.image_list) > 0:self.current_index = len(self.image_list) - 1if self.image_list:self.display_image()else:self.image_label.config(image='', text="没有图片")self.current_image_path = Noneself.update_status()self.save_config()except Exception as e:messagebox.showerror("错误", f"删除失败: {str(e)}")def update_status(self):if self.image_list:status = f"当前: {os.path.basename(self.current_image_path)} | 索引: {self.current_index + 1}/{len(self.image_list)}"else:status = "没有图片"self.status_label.config(text=status)def main():root = tk.Tk()root.geometry("1200x900")# 设置窗口图标(可选)# root.iconbitmap('icon.ico')app = ImageBrowser(root)root.mainloop()if __name__ == "__main__":main()