在这篇博客中,我们将探索如何使用 wxPython 创建一个 GUI 工具,用于选择文件夹中的照片文件、显示预览、选择并复制文件到指定目录,以及将选中的照片压缩到一个 ZIP 文件中。这个工具不仅功能强大,而且提供了用户友好的界面。
C:\pythoncode\new\photofilecopyandzip.py
全部代码
import wx
import os
from datetime import datetime
import shutil
import zipfileclass MyFrame(wx.Frame):def __init__(self, *args, **kwargs):super(MyFrame, self).__init__(*args, **kwargs)self.panel = wx.Panel(self)self.vbox = wx.BoxSizer(wx.VERTICAL)self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)self.openBtn = wx.Button(self.panel, label='Open Folder')self.selectAllBtn = wx.Button(self.panel, label='Select All')self.deselectAllBtn = wx.Button(self.panel, label='Deselect All')self.copyBtn = wx.Button(self.panel, label='Copy')self.compressBtn = wx.Button(self.panel, label='Compress')self.hbox1.Add(self.openBtn)self.hbox1.Add(self.selectAllBtn)self.hbox1.Add(self.deselectAllBtn)self.hbox1.Add(self.copyBtn)self.hbox1.Add(self.compressBtn)self.splitter = wx.SplitterWindow(self.panel)self.listView = wx.ListCtrl(self.splitter, style=wx.LC_REPORT | wx.BORDER_SUNKEN)self.listView.InsertColumn(0, 'Image Files')self.listView.InsertColumn(1, 'Size')self.listView.InsertColumn(2, 'Dimensions')self.listView.InsertColumn(3, 'Date')self.imagePreview = wx.StaticBitmap(self.splitter)self.splitter.SplitVertically(self.listView, self.imagePreview)self.splitter.SetSashGravity(0.5)self.vbox.Add(self.hbox1, 0, wx.EXPAND | wx.ALL, 5)self.vbox.Add(self.splitter, 1, wx.EXPAND)self.panel.SetSizer(self.vbox)self.Bind(wx.EVT_BUTTON, self.on_open_folder, self.openBtn)self.Bind(wx.EVT_BUTTON, self.on_select_all, self.selectAllBtn)self.Bind(wx.EVT_BUTTON, self.on_deselect_all, self.deselectAllBtn)self.Bind(wx.EVT_BUTTON, self.on_copy_photos, self.copyBtn)self.Bind(wx.EVT_BUTTON, self.on_compress_photos, self.compressBtn)self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected, self.listView)self.image_paths = {}self.selected_images = []def on_open_folder(self, event):with wx.DirDialog(self, "Choose a directory") as dlg:if dlg.ShowModal() == wx.ID_OK:folder_path = dlg.GetPath()self.load_images(folder_path)def load_images(self, folder_path):self.listView.DeleteAllItems()img_files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]items = [] # 存储将要插入的项信息for img_file in img_files:img_path = os.path.join(folder_path, img_file)img = wx.Image(img_path, wx.BITMAP_TYPE_ANY)if img.IsOk():size = os.path.getsize(img_path)dimensions = f"{img.GetWidth()}x{img.GetHeight()}"date = datetime.fromtimestamp(os.path.getmtime(img_path)).strftime('%Y-%m-%d %H:%M:%S')items.append((img_file, size, dimensions, date, img_path))# 批量插入项for index, (file_name, size, dimensions, date, img_path) in enumerate(items):item_index = self.listView.InsertItem(index, file_name)if item_index != -1:self.listView.SetItem(item_index, 1, f"{size} bytes")self.listView.SetItem(item_index, 2, dimensions)self.listView.SetItem(item_index, 3, date)self.image_paths[item_index] = img_pathself.listView.SetItem(item_index, 2, dimensions)self.listView.SetItem(item_index, 3, date)self.image_paths[item_index] = img_pathdef on_item_selected(self, event):self.show_image_preview(event.GetIndex())def show_image_preview(self, index):img_path = self.image_paths.get(index)if img_path and os.path.exists(img_path):img = wx.Image(img_path, wx.BITMAP_TYPE_ANY)if img.IsOk():W = img.GetWidth()H = img.GetHeight()NewW = int(W / 2)NewH = int(H / 2)img = img.Scale(NewW, NewH)self.imagePreview.SetBitmap(wx.Bitmap(img))self.imagePreview.Refresh()def on_select_all(self, event):item_count = self.listView.GetItemCount()for index in range(item_count):self.listView.Select(index)def on_deselect_all(self, event):item_count = self.listView.GetItemCount()for index in range(item_count):self.listView.Select(index, on=0)def on_copy_photos(self, event):with wx.DirDialog(self, "Choose a destination directory") as dlg:if dlg.ShowModal() == wx.ID_OK:dest_folder = dlg.GetPath()selected_items = [self.image_paths[index] for index in range(self.listView.GetItemCount()) if self.listView.IsSelected(index)]for img_path in selected_items:shutil.copy(img_path, dest_folder)def on_compress_photos(self, event):selected_items = [self.image_paths[index] for index in range(self.listView.GetItemCount()) if self.listView.IsSelected(index)]if selected_items:now = datetime.now().strftime("_%Y%m%d%H%M%S")folder_name = os.path.basename(os.path.dirname(selected_items[0])) + nowzip_filename = f"{folder_name}.zip"with zipfile.ZipFile(zip_filename, 'w') as zipf:for img_path in selected_items:zipf.write(img_path, os.path.basename(img_path))if __name__ == "__main__":app = wx.App(False)frame = MyFrame(None, title="Photo File Copy and Zip")frame.Show()app.MainLoop()
步骤 1:设置开发环境
首先,我们需要安装 wxPython。如果还没有安装,可以通过以下命令安装:
pip install wxPython
步骤 2:创建 GUI 界面
我们将从创建一个简单的 GUI 界面开始。界面包括按钮、列表视图和图片预览窗口。
import wx
import os
from datetime import datetime
import shutil
import zipfileclass MyFrame(wx.Frame):def __init__(self, *args, **kwargs):super(MyFrame, self).__init__(*args, **kwargs)self.panel = wx.Panel(self)self.vbox = wx.BoxSizer(wx.VERTICAL)self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)self.openBtn = wx.Button(self.panel, label='Open Folder')self.selectAllBtn = wx.Button(self.panel, label='Select All')self.deselectAllBtn = wx.Button(self.panel, label='Deselect All')self.copyBtn = wx.Button(self.panel, label='Copy')self.compressBtn = wx.Button(self.panel, label='Compress')self.hbox1.Add(self.openBtn)self.hbox1.Add(self.selectAllBtn)self.hbox1.Add(self.deselectAllBtn)self.hbox1.Add(self.copyBtn)self.hbox1.Add(self.compressBtn)self.splitter = wx.SplitterWindow(self.panel)self.listView = wx.ListCtrl(self.splitter, style=wx.LC_REPORT | wx.BORDER_SUNKEN)self.listView.InsertColumn(0, 'Image Files')self.listView.InsertColumn(1, 'Size')self.listView.InsertColumn(2, 'Dimensions')self.listView.InsertColumn(3, 'Date')self.imagePreview = wx.StaticBitmap(self.splitter)self.splitter.SplitVertically(self.listView, self.imagePreview)self.splitter.SetSashGravity(0.5)self.vbox.Add(self.hbox1, 0, wx.EXPAND | wx.ALL, 5)self.vbox.Add(self.splitter, 1, wx.EXPAND)self.panel.SetSizer(self.vbox)self.Bind(wx.EVT_BUTTON, self.on_open_folder, self.openBtn)self.Bind(wx.EVT_BUTTON, self.on_select_all, self.selectAllBtn)self.Bind(wx.EVT_BUTTON, self.on_deselect_all, self.deselectAllBtn)self.Bind(wx.EVT_BUTTON, self.on_copy_photos, self.copyBtn)self.Bind(wx.EVT_BUTTON, self.on_compress_photos, self.compressBtn)self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected, self.listView)self.image_paths = {}self.selected_images = []def on_open_folder(self, event):with wx.DirDialog(self, "Choose a directory") as dlg:if dlg.ShowModal() == wx.ID_OK:folder_path = dlg.GetPath()self.load_images(folder_path)def load_images(self, folder_path):self.listView.DeleteAllItems()img_files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]for index, img_file in enumerate(img_files):img_path = os.path.join(folder_path, img_file)img = wx.Image(img_path, wx.BITMAP_TYPE_ANY)if img.IsOk():size = os.path.getsize(img_path)dimensions = f"{img.GetWidth()}x{img.GetHeight()}"date = datetime.fromtimestamp(os.path.getmtime(img_path)).strftime('%Y-%m-%d %H:%M:%S')item_index = self.listView.InsertItem(index, img_file)if item_index != -1:self.listView.SetItem(item_index, 1, f"{size} bytes")self.listView.SetItem(item_index, 2, dimensions)self.listView.SetItem(item_index, 3, date)self.image_paths[item_index] = img_pathdef on_item_selected(self, event):self.show_image_preview(event.GetIndex())def show_image_preview(self, index):img_path = self.image_paths.get(index)if img_path and os.path.exists(img_path):img = wx.Image(img_path, wx.BITMAP_TYPE_ANY)if img.IsOk():W = img.GetWidth()H = img.GetHeight()NewW = int(W / 2)NewH = int(H / 2)img = img.Scale(NewW, NewH)self.imagePreview.SetBitmap(wx.Bitmap(img))self.imagePreview.Refresh()def on_select_all(self, event):item_count = self.listView.GetItemCount()for index in range(item_count):self.listView.Select(index)def on_deselect_all(self, event):item_count = self.listView.GetItemCount()for index in range(item_count):self.listView.Select(index, on=0)def on_copy_photos(self, event):with wx.DirDialog(self, "Choose a destination directory") as dlg:if dlg.ShowModal() == wx.ID_OK:dest_folder = dlg.GetPath()selected_items = [self.image_paths[index] for index in range(self.listView.GetItemCount()) if self.listView.IsSelected(index)]for img_path in selected_items:shutil.copy(img_path, dest_folder)def on_compress_photos(self, event):selected_items = [self.image_paths[index] for index in range(self.listView.GetItemCount()) if self.listView.IsSelected(index)]if selected_items:now = datetime.now().strftime("_%Y%m%d%H%M%S")folder_name = os.path.basename(os.path.dirname(selected_items[0])) + nowzip_filename = f"{folder_name}.zip"with zipfile.ZipFile(zip_filename, 'w') as zipf:for img_path in selected_items:zipf.write(img_path, os.path.basename(img_path))if __name__ == "__main__":app = wx.App(False)frame = MyFrame(None, title="Photo File Copy and Zip")frame.Show()app.MainLoop()
步骤 3:运行和测试
保存上述代码到一个文件(例如 photofilecopyandzip.py
),然后在命令行运行:
python photofilecopyandzip.py
你将看到一个 GUI 窗口,其中包含各种按钮和一个列表视图。点击“Open Folder”按钮选择包含照片的文件夹,照片文件将显示在列表视图中。你可以选择全部或部分照片,然后选择复制到另一个文件夹或者压缩为 ZIP 文件。
关键功能解析
-
打开文件夹:
使用wx.DirDialog
打开文件夹对话框,选择包含照片的文件夹。通过os.listdir
获取文件夹中的文件列表,并使用wx.Image
加载并显示图片。 -
显示图片预览:
当用户选择列表中的图片时,使用wx.StaticBitmap
显示图片的缩略图。 -
选择和取消选择:
提供全选和取消选择按钮,便于用户批量选择和取消选择照片文件。 -
复制照片:
通过shutil.copy
将选中的照片文件复制到指定目录。 -
压缩照片:
使用zipfile.ZipFile
创建 ZIP 文件,将选中的照片文件添加到 ZIP 文件中。
结果如下
结论
通过这篇博客,我们创建了一个功能全面的照片文件管理工具,能够帮助用户方便地选择、预览、复制和压缩照片文件。这个工具展示了 wxPython 在创建桌面应用程序时的强大功能和灵活性。希望你能从中学到有用的知识,并将其应用到你自己的项目中。