py一个文件夹图片浏览和删除脚本
AI生成内容
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 = root
self.root.title("图片浏览器")
# 配置文件路径
self.config_file = "image_browser_config.ini"
# 图片列表和当前索引
self.image_list = []
self.current_index = 0
self.current_image_path = None
self.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('<Up>', lambda e: self.previous_image())
self.root.bind('<Down>', lambda e: self.next_image())
self.root.bind('<Delete>', lambda e: self.delete_image())
self.root.bind('d', lambda e: self.delete_image())
self.root.bind('D', 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()
current_dir = os.path.join(os.getcwd(), "images")
self.dir_entry.insert(0, current_dir)
self.current_directory = 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/d)", 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):
current_directory = self.current_directory
if not os.path.exists(current_directory):
current_directory = os.getcwd()
directory = filedialog.askdirectory(initialdir=current_directory)
if directory:
self.dir_entry.delete(0, tk.END)
self.dir_entry.insert(0, directory)
self.load_images()
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("警告", "请输入或选择目录")
return
if 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) - 1
if self.current_index < 0:
self.current_index = 0
# 尝试读取图片,如果失败则跳过到下一张
max_attempts = len(self.image_list)
attempts = 0
pil_img = None
while attempts < max_attempts:
self.current_image_path = self.image_list[self.current_index]
# 使用PIL读取图片
try:
pil_img = Image.open(self.current_image_path)
break
except Exception as e:
# 无法读取图片,跳过
print(f"无法读取图片: {self.current_image_path}, 错误: {e}")
attempts += 1
# 移动到下一张
self.current_index += 1
if self.current_index >= len(self.image_list):
self.current_index = 0
if 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.size
max_width = 1100
max_height = 750
if 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)
# 创建PhotoImage
photo = 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:
return
self.current_index -= 1
if self.current_index < 0:
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("提示", "已经是第一张图片")
return
self.display_image()
self.update_status()
def next_image(self):
if not self.image_list:
return
self.current_index += 1
if 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("提示", "已回到第一张图片")
return
self.display_image()
self.update_status()
def delete_image(self):
if not self.image_list:
return
if not self.current_image_path:
return
try:
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) - 1
if self.image_list:
self.display_image()
else:
self.image_label.config(image='', text="没有图片")
self.current_image_path = None
self.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 create_icon():
"""创建图标文件"""
try:
from PIL import Image, ImageDraw
# 图标尺寸
sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
# 创建不同尺寸的图标
images = []
for size in sizes:
# 创建图像
img = Image.new('RGBA', size, (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# 绘制背景圆角矩形
margin = size[0] // 8
draw.rounded_rectangle(
[margin, margin, size[0] - margin, size[1] - margin],
radius=size[0] // 4,
fill=(70, 130, 180, 255) # 钢蓝色
)
# 绘制图片图标(简单的矩形框)
img_margin = size[0] // 4
img_size = size[0] - 2 * img_margin
draw.rectangle(
[img_margin, img_margin, img_margin + img_size, img_margin + img_size],
outline=(255, 255, 255, 255),
width=max(1, size[0] // 32)
)
# 绘制简单的"山"形(代表图片)
mountain_margin = size[0] // 3
mountain_top = size[1] - size[1] // 3
mountain_bottom = size[1] - size[1] // 6
# 左边的山
draw.polygon([
(mountain_margin, mountain_bottom),
(mountain_margin + img_size // 3, mountain_margin + img_size // 4),
(mountain_margin + img_size // 2, mountain_bottom)
], fill=(255, 255, 255, 200))
# 右边的山
draw.polygon([
(mountain_margin + img_size // 2, mountain_bottom),
(mountain_margin + img_size * 2 // 3, mountain_margin + img_size // 3),
(mountain_margin + img_size, mountain_bottom)
], fill=(255, 255, 255, 200))
# 太阳
sun_radius = size[0] // 16
sun_center = (mountain_margin + img_size // 8, mountain_margin + img_size // 8)
draw.ellipse(
[sun_center[0] - sun_radius, sun_center[1] - sun_radius,
sun_center[0] + sun_radius, sun_center[1] + sun_radius],
fill=(255, 200, 100, 255)
)
images.append(img)
return images
except ImportError:
print("警告: 未安装PIL库,无法创建图标")
print("将使用默认图标")
return None
except Exception as e:
print(f"创建图标失败: {e}")
print("将使用默认图标")
return None
def main():
root = tk.Tk()
img=create_icon()
photo = ImageTk.PhotoImage(img[1])
root.iconphoto(True, photo)# 设置图标
root.geometry("1200x900")
# 设置窗口图标
try:
if os.path.exists('icon.ico'):
root.iconbitmap('icon.ico')
except Exception as e:
print(f"设置图标失败: {e}")
app = ImageBrowser(root)
root.mainloop()
if __name__ == "__main__":
main()
打包脚本 pyinstaller --name=ImageBrowser --onefile --windowed --icon=icon.ico --clean --noconfirm image_browser.py
"""
打包脚本 - 使用PyInstaller将image_browser.py打包为exe
"""
import os
import sys
import subprocess
def create_icon():
"""创建图标文件"""
try:
from PIL import Image, ImageDraw
# 图标尺寸
sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
# 创建不同尺寸的图标
images = []
for size in sizes:
# 创建图像
img = Image.new('RGBA', size, (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# 绘制背景圆角矩形
margin = size[0] // 8
draw.rounded_rectangle(
[margin, margin, size[0] - margin, size[1] - margin],
radius=size[0] // 4,
fill=(70, 130, 180, 255) # 钢蓝色
)
# 绘制图片图标(简单的矩形框)
img_margin = size[0] // 4
img_size = size[0] - 2 * img_margin
draw.rectangle(
[img_margin, img_margin, img_margin + img_size, img_margin + img_size],
outline=(255, 255, 255, 255),
width=max(1, size[0] // 32)
)
# 绘制简单的"山"形(代表图片)
mountain_margin = size[0] // 3
mountain_top = size[1] - size[1] // 3
mountain_bottom = size[1] - size[1] // 6
# 左边的山
draw.polygon([
(mountain_margin, mountain_bottom),
(mountain_margin + img_size // 3, mountain_margin + img_size // 4),
(mountain_margin + img_size // 2, mountain_bottom)
], fill=(255, 255, 255, 200))
# 右边的山
draw.polygon([
(mountain_margin + img_size // 2, mountain_bottom),
(mountain_margin + img_size * 2 // 3, mountain_margin + img_size // 3),
(mountain_margin + img_size, mountain_bottom)
], fill=(255, 255, 255, 200))
# 太阳
sun_radius = size[0] // 16
sun_center = (mountain_margin + img_size // 8, mountain_margin + img_size // 8)
draw.ellipse(
[sun_center[0] - sun_radius, sun_center[1] - sun_radius,
sun_center[0] + sun_radius, sun_center[1] + sun_radius],
fill=(255, 200, 100, 255)
)
images.append(img)
# 保存为ICO文件
icon_path = "icon.ico"
images[0].save(
icon_path,
format='ICO',
sizes=[(img.width, img.height) for img in images]
)
print(f"图标已创建: {icon_path}")
return icon_path
except ImportError:
print("警告: 未安装PIL库,无法创建图标")
print("将使用默认图标")
return None
except Exception as e:
print(f"创建图标失败: {e}")
print("将使用默认图标")
return None
def build_exe():
"""打包为exe文件"""
# 创建图标
print("步骤 1/3: 创建图标...")
icon_path = create_icon()
if icon_path:
print(f"✓ 图标创建成功\n")
else:
print("✓ 使用默认图标\n")
# PyInstaller命令
print("步骤 2/3: 开始打包...")
cmd = [
'pyinstaller',
'--name=ImageBrowser',
'--onefile',
'--windowed',
]
# 如果图标创建成功,添加图标参数
if icon_path and os.path.exists(icon_path):
cmd.append(f'--icon={icon_path}')
else:
cmd.append('--icon=NONE')
cmd.extend([
'--clean',
'--noconfirm',
'image_browser.py'
])
print(f"命令: {' '.join(cmd)}\n")
try:
# 执行打包命令
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("✓ 打包成功!")
print(result.stdout)
# 检查生成的exe文件
exe_path = os.path.join('dist', 'ImageBrowser.exe')
if os.path.exists(exe_path):
file_size = os.path.getsize(exe_path) / (1024 * 1024) # MB
print(f"\n步骤 3/3: 验证生成的文件")
print(f"✓ EXE文件: {exe_path}")
print(f"✓ 文件大小: {file_size:.2f} MB")
else:
print("\n警告: 未找到生成的exe文件")
except subprocess.CalledProcessError as e:
print("✗ 打包失败!")
print(f"错误信息: {e.stderr}")
sys.exit(1)
except FileNotFoundError:
print("✗ 错误: 未找到pyinstaller命令")
print("请先安装PyInstaller: pip install pyinstaller")
sys.exit(1)
if __name__ == "__main__":
print("=" * 50)
print(" 图片浏览器 - EXE打包工具")
print("=" * 50)
print()
build_exe()
print()
print("=" * 50)
print(" 打包完成!")
print("=" * 50)
一个改进版本
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import configparser
class ImageBrowser:
def __init__(self, root):
self.root = root
self.root.title("图片浏览器")
# 配置文件路径
self.config_file = "image_browser_config.ini"
# 图片列表和当前索引
self.image_list = []
self.current_index = 0
self.current_image_path = None
self.current_directory = ""
# 图片显示相关
self.original_image = None # 原始图片
self.displayed_image = None # 显示的图片
self.scale_factor = 1.0 # 缩放因子
self.offset_x = 0 # X偏移
self.offset_y = 0 # Y偏移
self.drag_start_x = 0 # 拖动起始X
self.drag_start_y = 0 # 拖动起始Y
# 创建界面
self.create_widgets()
# 绑定快捷键
self.root.bind('<Left>', lambda e: self.previous_image())
self.root.bind('<Right>', lambda e: self.next_image())
self.root.bind('<Up>', lambda e: self.previous_image())
self.root.bind('<Down>', lambda e: self.next_image())
self.root.bind('<Delete>', lambda e: self.delete_image())
self.root.bind('d', lambda e: self.delete_image())
self.root.bind('D', 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.path.join(os.getcwd(), "images")
self.dir_entry.insert(0, current_dir)
self.current_directory = 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)
# 图片显示区域(使用Canvas支持滚动和拖动)
self.canvas_frame = tk.Frame(self.root)
self.canvas_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
self.canvas = tk.Canvas(self.canvas_frame, bg="gray")
self.canvas.pack(fill=tk.BOTH, expand=True)
# 绑定鼠标事件
self.canvas.bind('<MouseWheel>', self.on_mouse_wheel) # Windows
self.canvas.bind('<Button-4>', self.on_mouse_wheel) # Linux scroll up
self.canvas.bind('<Button-5>', self.on_mouse_wheel) # Linux scroll down
self.canvas.bind('<ButtonPress-1>', self.on_mouse_press) # 鼠标按下
self.canvas.bind('<B1-Motion>', self.on_mouse_drag) # 鼠标拖动
self.canvas.bind('<ButtonRelease-1>', self.on_mouse_release) # 鼠标释放
# 按钮区域
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/d)", 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 on_mouse_wheel(self, event):
"""鼠标滚轮缩放"""
if not self.original_image:
return
# 确定缩放方向
if event.num == 5 or event.delta < 0:
# 向下滚动,缩小
new_scale = self.scale_factor * 0.9
else:
# 向上滚动,放大
new_scale = self.scale_factor * 1.1
# 限制缩放范围
if new_scale < 0.1:
new_scale = 0.1
elif new_scale > 10.0:
new_scale = 10.0
# 计算缩放中心(鼠标位置)
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
mouse_x = event.x
mouse_y = event.y
# 计算缩放前的图片中心相对于鼠标的位置
old_image_x = mouse_x - self.offset_x
old_image_y = mouse_y - self.offset_y
# 更新缩放因子
self.scale_factor = new_scale
# 计算新的偏移量,使缩放中心保持在鼠标位置
self.offset_x = mouse_x - old_image_x * (new_scale / self.scale_factor)
self.offset_y = mouse_y - old_image_y * (new_scale / self.scale_factor)
# 重新显示图片
self.display_scaled_image()
def on_mouse_press(self, event):
"""鼠标按下"""
self.drag_start_x = event.x
self.drag_start_y = event.y
def on_mouse_drag(self, event):
"""鼠标拖动"""
if not self.original_image:
return
# 计算拖动距离
dx = event.x - self.drag_start_x
dy = event.y - self.drag_start_y
# 更新偏移量
self.offset_x += dx
self.offset_y += dy
# 更新起始位置
self.drag_start_x = event.x
self.drag_start_y = event.y
# 重新显示图片
self.display_scaled_image()
def on_mouse_release(self, event):
"""鼠标释放"""
pass
def browse_directory(self):
current_directory = self.current_directory
if not os.path.exists(current_directory):
current_directory = os.getcwd()
directory = filedialog.askdirectory(initialdir=current_directory)
if directory:
self.dir_entry.delete(0, tk.END)
self.dir_entry.insert(0, directory)
self.load_images()
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("警告", "请输入或选择目录")
return
if 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.canvas.delete("all")
self.canvas.create_text(400, 300, text="没有图片", fill="white", font=("Arial", 20))
return
# 确保索引在有效范围内
if self.current_index >= len(self.image_list):
self.current_index = len(self.image_list) - 1
if self.current_index < 0:
self.current_index = 0
# 尝试读取图片,如果失败则跳过到下一张
max_attempts = len(self.image_list)
attempts = 0
while attempts < max_attempts:
self.current_image_path = self.image_list[self.current_index]
# 使用PIL读取图片
try:
self.original_image = Image.open(self.current_image_path)
break
except Exception as e:
# 无法读取图片,跳过
print(f"无法读取图片: {self.current_image_path}, 错误: {e}")
attempts += 1
# 移动到下一张
self.current_index += 1
if self.current_index >= len(self.image_list):
self.current_index = 0
if attempts >= max_attempts:
messagebox.showerror("错误", "无法读取任何图片")
self.canvas.delete("all")
self.canvas.create_text(400, 300, text="无法读取图片", fill="white", font=("Arial", 20))
return
# 转换为RGB模式(如果需要)
if self.original_image.mode != 'RGB':
self.original_image = self.original_image.convert('RGB')
# 重置偏移
self.offset_x = 0
self.offset_y = 0
# 获取画布尺寸
self.root.update() # 确保窗口已更新
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
# 如果画布尺寸为0(窗口未完全初始化),使用默认值
if canvas_width <= 1:
canvas_width = 1100
if canvas_height <= 1:
canvas_height = 750
# 计算图片原始尺寸
img_width, img_height = self.original_image.size
# 如果图片尺寸超过画布,自动缩放以适应画布
if img_width > canvas_width or img_height > canvas_height:
scale_width = canvas_width / img_width
scale_height = canvas_height / img_height
self.scale_factor = min(scale_width, scale_height) # 使用较小的缩放比例
# 留一点边距
self.scale_factor *= 0.95
else:
self.scale_factor = 1.0
# 显示图片
self.display_scaled_image()
# 更新窗口标题
self.root.title(f"图片浏览器 - {os.path.basename(self.current_image_path)} ({self.current_index + 1}/{len(self.image_list)})")
# 保存配置
self.save_config()
def display_scaled_image(self):
"""显示缩放后的图片"""
if not self.original_image:
return
# 计算缩放后的尺寸
w, h = self.original_image.size
new_w = int(w * self.scale_factor)
new_h = int(h * self.scale_factor)
# 缩放图片
if self.scale_factor != 1.0:
scaled_image = self.original_image.resize((new_w, new_h), Image.LANCZOS)
else:
scaled_image = self.original_image
# 转换为PhotoImage
self.displayed_image = ImageTk.PhotoImage(scaled_image)
# 清除画布
self.canvas.delete("all")
# 获取画布尺寸
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
# 如果画布尺寸为0(窗口未完全初始化),使用默认值
if canvas_width <= 1:
canvas_width = 1100
if canvas_height <= 1:
canvas_height = 750
# 计算居中位置(如果没有拖动偏移)
if self.offset_x == 0 and self.offset_y == 0:
center_x = canvas_width // 2
center_y = canvas_height // 2
self.canvas.create_image(
center_x, center_y,
anchor=tk.CENTER,
image=self.displayed_image
)
else:
# 使用拖动偏移
self.canvas.create_image(
self.offset_x, self.offset_y,
anchor=tk.NW,
image=self.displayed_image
)
def previous_image(self):
if not self.image_list:
return
self.current_index -= 1
if self.current_index < 0:
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("提示", "已经是第一张图片")
return
self.display_image()
self.update_status()
def next_image(self):
if not self.image_list:
return
self.current_index += 1
if 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("提示", "已回到第一张图片")
return
self.display_image()
self.update_status()
def delete_image(self):
if not self.image_list:
return
if not self.current_image_path:
return
try:
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) - 1
if self.image_list:
self.display_image()
else:
self.canvas.delete("all")
self.canvas.create_text(400, 300, text="没有图片", fill="white", font=("Arial", 20))
self.current_image_path = None
self.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)} | 缩放: {self.scale_factor:.1f}x"
else:
status = "没有图片"
self.status_label.config(text=status)
def create_icon():
"""创建图标文件"""
try:
from PIL import Image, ImageDraw
# 图标尺寸
sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
# 创建不同尺寸的图标
images = []
for size in sizes:
# 创建图像
img = Image.new('RGBA', size, (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# 绘制背景圆角矩形
margin = size[0] // 8
draw.rounded_rectangle(
[margin, margin, size[0] - margin, size[1] - margin],
radius=size[0] // 4,
fill=(70, 130, 180, 255) # 钢蓝色
)
# 绘制图片图标(简单的矩形框)
img_margin = size[0] // 4
img_size = size[0] - 2 * img_margin
draw.rectangle(
[img_margin, img_margin, img_margin + img_size, img_margin + img_size],
outline=(255, 255, 255, 255),
width=max(1, size[0] // 32)
)
# 绘制简单的"山"形(代表图片)
mountain_margin = size[0] // 3
mountain_top = size[1] - size[1] // 3
mountain_bottom = size[1] - size[1] // 6
# 左边的山
draw.polygon([
(mountain_margin, mountain_bottom),
(mountain_margin + img_size // 3, mountain_margin + img_size // 4),
(mountain_margin + img_size // 2, mountain_bottom)
], fill=(255, 255, 255, 200))
# 右边的山
draw.polygon([
(mountain_margin + img_size // 2, mountain_bottom),
(mountain_margin + img_size * 2 // 3, mountain_margin + img_size // 3),
(mountain_margin + img_size, mountain_bottom)
], fill=(255, 255, 255, 200))
# 太阳
sun_radius = size[0] // 16
sun_center = (mountain_margin + img_size // 8, mountain_margin + img_size // 8)
draw.ellipse(
[sun_center[0] - sun_radius, sun_center[1] - sun_radius,
sun_center[0] + sun_radius, sun_center[1] + sun_radius],
fill=(255, 200, 100, 255)
)
images.append(img)
# # 保存为ICO文件
# icon_path = "icon.ico"
# images[0].save(
# icon_path,
# format='ICO',
# sizes=[(img.width, img.height) for img in images]
# )
# print(f"图标已创建: {icon_path}")
return images
except ImportError:
print("警告: 未安装PIL库,无法创建图标")
print("将使用默认图标")
return None
except Exception as e:
print(f"创建图标失败: {e}")
print("将使用默认图标")
return None
def main():
root = tk.Tk()
root.geometry("1200x900")
# 设置窗口图标
try:
images = create_icon()
if images:
photo = ImageTk.PhotoImage(images[1])
root.iconphoto(True, photo)
except Exception as e:
print(f"设置图标失败: {e}")
app = ImageBrowser(root)
root.mainloop()
if __name__ == "__main__":
main()

浙公网安备 33010602011771号