每一步的代码都加上了注释
[Python] 纯文本查看 复制代码# 导入 wxPython 库,用于创建图形用户界面
import wx
# 导入 os 模块,用于进行文件和目录操作
import os
# 从 PIL 库中导入 Image 模块,用于处理图片
from PIL import Image
# 导入 threading 模块,用于实现多线程操作
import threading
# 定义滚动面板类,继承自 wx.ScrolledWindow
class ScrollablePanel(wx.ScrolledWindow):
# 类的初始化方法
def __init__(self, parent):
# 调用父类的初始化方法
super().__init__(parent)
# 创建一个垂直的 BoxSizer 用于布局管理
self.sizer = wx.BoxSizer(wx.VERTICAL)
# 将该 sizer 设置给当前窗口
self.SetSizer(self.sizer)
# 设置滚动的速率
self.SetScrollRate(5, 5)
# 自定义文件拖拽目标类,继承自 wx.FileDropTarget
class MyFileDropTarget(wx.FileDropTarget):
# 类的初始化方法
def __init__(self, window):
# 调用父类的初始化方法
wx.FileDropTarget.__init__(self)
# 保存传入的窗口对象
self.window = window
# 当有文件拖拽到目标区域时触发的方法
def OnDropFiles(self, x, y, filenames):
# 调用窗口对象的 add_images 方法处理拖拽的文件
self.window.add_images(filenames)
return True
# 定义图片压缩应用程序类,继承自 wx.Frame
class ImageCompressorApp(wx.Frame):
# 类的初始化方法
def __init__(self):
# 调用父类的初始化方法,设置窗口标题和大小
super().__init__(None, title="图片批量压缩工具", size=(1200, 800))
# 创建主面板
self.panel = wx.Panel(self)
# 创建顶部标题标签
title_label = wx.StaticText(self.panel, label="图片批量压缩工具", style=wx.ALIGN_CENTER,
pos=(0, 10), size=(1200, -1))
# 设置标题字体
font = wx.Font(36, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
title_label.SetFont(font)
# 创建操作按钮和设置区域的面板
button_panel = wx.Panel(self.panel)
# 创建批量选择图片按钮
select_button = wx.Button(button_panel, label="批量选择图片", size=(200, 30))
# 创建清理已压缩文件按钮
clear_button = wx.Button(button_panel, label="清理已压缩文件", size=(200, 30))
# 创建一个水平的 BoxSizer 用于按钮布局
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
# 将选择按钮添加到 sizer 中
button_sizer.Add(select_button, 0, wx.ALL, 10)
# 将清理按钮添加到 sizer 中
button_sizer.Add(clear_button, 0, wx.ALL, 10)
# 将 sizer 设置给按钮面板
button_panel.SetSizer(button_sizer)
# 创建拖拽区域的面板
self.drop_panel = wx.Panel(self.panel, style=wx.BORDER_SUNKEN)
# 创建拖拽提示标签
drop_label = wx.StaticText(self.drop_panel, label="拖拽图片到此处", style=wx.ALIGN_CENTER)
# 设置拖拽提示标签的字体
drop_font = wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL)
drop_label.SetFont(drop_font)
# 创建一个垂直的 BoxSizer 用于拖拽区域布局
drop_sizer = wx.BoxSizer(wx.VERTICAL)
# 将拖拽提示标签添加到 sizer 中
drop_sizer.Add(drop_label, 1, wx.EXPAND | wx.ALL, 50)
# 将 sizer 设置给拖拽面板
self.drop_panel.SetSizer(drop_sizer)
# 创建文件拖拽目标实例
dt = MyFileDropTarget(self)
# 将拖拽目标设置给拖拽面板
self.drop_panel.SetDropTarget(dt)
# 创建滚动区域面板
self.scroll_panel = ScrollablePanel(self.panel)
# 初始化图片路径列表
self.image_paths = []
# 初始化进度条列表
self.progress_bars = []
# 初始化图片信息标签列表
self.image_labels = []
# 创建主布局 sizer
main_sizer = wx.BoxSizer(wx.VERTICAL)
# 将标题标签添加到主 sizer 中
main_sizer.Add(title_label, 0, wx.EXPAND | wx.ALL, 10)
# 将按钮面板添加到主 sizer 中
main_sizer.Add(button_panel, 0, wx.EXPAND | wx.ALL, 10)
# 将拖拽面板添加到主 sizer 中
main_sizer.Add(self.drop_panel, 1, wx.EXPAND | wx.ALL, 20)
# 将滚动面板添加到主 sizer 中
main_sizer.Add(self.scroll_panel, 1, wx.EXPAND | wx.ALL, 10)
# 将主 sizer 设置给主面板
self.panel.SetSizer(main_sizer)
# 绑定选择图片按钮的点击事件到 select_images 方法
select_button.Bind(wx.EVT_BUTTON, self.select_images)
# 绑定清理已压缩文件按钮的点击事件到 clear_compressed_files 方法
clear_button.Bind(wx.EVT_BUTTON, self.clear_compressed_files)
# 处理文件拖拽事件的方法
def on_drop(self, event):
# 获取拖拽的文件路径列表
file_paths = event.GetFiles()
# 调用 add_images 方法处理文件路径列表
self.add_images(file_paths)
# 处理选择图片按钮点击事件的方法
def select_images(self, event):
# 创建文件选择对话框
dlg = wx.FileDialog(self, "选择图片", wildcard="图片文件 (*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.tiff)|*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.tiff",
style=wx.FD_OPEN | wx.FD_MULTIPLE)
# 显示对话框并判断用户是否点击了确定按钮
if dlg.ShowModal() == wx.ID_OK:
# 获取用户选择的文件路径列表
file_paths = dlg.GetPaths()
# 调用 add_images 方法处理文件路径列表
self.add_images(file_paths)
# 销毁对话框
dlg.Destroy()
# 添加图片到处理列表的方法
def add_images(self, file_paths):
# 遍历文件路径列表
for path in file_paths:
# 判断路径是否为文件
if os.path.isfile(path):
# 将文件路径添加到图片路径列表中
self.image_paths.append(path)
# 获取图片原始大小并转换为 KB
original_size = os.path.getsize(path) / 1024
# 获取文件名
file_name = os.path.basename(path)
# 生成图片信息标签文本
label_text = f"{file_name} 原大小:{original_size:.2f}Kb 压缩后大小:未处理 压缩比:未处理"
# 创建图片信息标签
file_name_label = wx.StaticText(self.scroll_panel, label=label_text)
# 设置图片信息标签的字体
label_font = wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
file_name_label.SetFont(label_font)
# 将图片信息标签添加到标签列表中
self.image_labels.append(file_name_label)
# 创建进度条
progress_bar = wx.Gauge(self.scroll_panel, range=100)
# 将进度条添加到进度条列表中
self.progress_bars.append(progress_bar)
# 将图片信息标签添加到滚动面板的 sizer 中
self.scroll_panel.sizer.Add(file_name_label, 0, wx.ALL, 10)
# 将进度条添加到滚动面板的 sizer 中
self.scroll_panel.sizer.Add(progress_bar, 0, wx.ALL | wx.EXPAND, 10)
# 重新布局滚动面板的 sizer
self.scroll_panel.sizer.Layout()
# 设置滚动面板的虚拟大小
self.scroll_panel.SetVirtualSize(self.scroll_panel.sizer.GetMinSize())
# 启动一个新线程执行图片压缩操作
threading.Thread(target=self.start_compression).start()
# 开始图片压缩的方法
def start_compression(self):
# 判断压缩后文件夹是否存在,不存在则创建
if not os.path.exists("压缩后"):
os.makedirs("压缩后")
# 遍历图片路径列表
for i, path in enumerate(self.image_paths):
# 调用 compress_image 方法压缩图片
self.compress_image(path, i)
# 压缩图片的方法
def compress_image(self, path, index):
try:
# 获取图片原始大小并转换为 KB
original_size = os.path.getsize(path) / 1024
# 打开图片
img = Image.open(path)
# 获取文件名
file_name = os.path.basename(path)
# 生成压缩后图片的输出路径
output_path = os.path.join("压缩后", file_name)
# 设置进度条的总步数
total_steps = 100
# 模拟进度条更新
for step in range(total_steps):
# 调用 wx.CallAfter 在主线程中更新进度条的值
wx.CallAfter(self.progress_bars[index].SetValue, step + 1)
# 获取文件扩展名并转换为小写
file_extension = os.path.splitext(file_name)[1].lower()
# 生成临时文件路径
temp_path = os.path.join("压缩后", f"temp_{file_name}")
# 初始化最佳压缩大小为原始大小
best_size = original_size
# 初始化最佳压缩路径为原始路径
best_path = path
# 如果文件扩展名是 .png
if file_extension in ['.png']:
# 以压缩级别 3 保存图片到临时路径
img.save(temp_path, compress_level=3)
# 获取临时文件的大小并转换为 KB
compressed_size = os.path.getsize(temp_path) / 1024
# 如果临时文件大小小于最佳大小
if compressed_size