WxPython跨平台开发框架之表格数据导出到Excel并打开

打印 上一主题 下一主题

主题 749|帖子 749|积分 2247

在 Python 中使用 wxPython 导出实体类列表数据到 Excel,通常可以借助 openpyxl 或 pandas 库来实现。本篇随笔由浅入深,逐步介绍导出Excel文件的操作,然后结合跨平台项目标实现,根据抽象继承的方式,对不同业务模块的通用导出Excel文件功能,以及跨平台的打开处置惩罚方式的实现举行介绍。
以下是一个基本示例,展示如何将实体类的列表数据导出到 Excel 文件。
1、使用pandas 库导出Excel
  1. import wx
  2. import pandas as pd
  3. # 假设这是你的实体类
  4. class Person:
  5.     def __init__(self, name, age, email):
  6.         self.name = name
  7.         self.age = age
  8.         self.email = email
  9.     def to_dict(self):
  10.         return {"Name": self.name, "Age": self.age, "Email": self.email}
  11. # 用一个 wxPython 窗口展示如何导出数据
  12. class MyFrame(wx.Frame):
  13.     def __init__(self, parent, title):
  14.         super().__init__(parent, title=title, size=(300, 200))
  15.         
  16.         self.panel = wx.Panel(self)
  17.         self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
  18.         
  19.         # 创建一些实体类数据
  20.         self.person_list = [
  21.             Person("Alice", 30, "alice@example.com"),
  22.             Person("Bob", 25, "bob@example.com"),
  23.             Person("Charlie", 35, "charlie@example.com")
  24.         ]
  25.         
  26.         self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
  27.         self.Show()
  28.     def export_to_excel(self, event):
  29.         # 将实体类列表转换为字典列表
  30.         data = [person.to_dict() for person in self.person_list]
  31.         
  32.         # 使用 pandas 导出到 Excel
  33.         df = pd.DataFrame(data)
  34.         df.to_excel("exported_data.xlsx", index=False)
  35.         
  36.         wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)
  37. # 启动 wxPython 应用
  38. app = wx.App(False)
  39. frame = MyFrame(None, "导出实体类数据到 Excel")
  40. app.MainLoop()
复制代码
实体类 (Person):包罗一些字段,如 name、age 和 email,并定义了 to_dict 方法,将实体对象转换为字典格式,以便更轻易处置惩罚。
export_to_excel:这个方法将实体类列表转换为字典列表,使用 pandas 库将数据导出为 Excel 文件。
假如你需要更多的功能(如自定义 Excel 格式,单位格样式等),可以进一步扩展 openpyxl 或 xlsxwriter 来提供更复杂的导出选项。
 
2、使用 openpyxl 库导出Excel

要在 Excel 导出时为标题加粗并设置背景色,你可以使用 openpyxl 库,它提供了丰富的功能来设置单位格样式(如字体、背景色等)。
以下是一个更新的示例,演示如何在导出数据时,设置 Excel 标题行的加粗和背景色。
  1. import wx
  2. from openpyxl import Workbook
  3. from openpyxl.styles import Font, PatternFill
  4. # 假设这是你的实体类
  5. class Person:
  6.     def __init__(self, name, age, email):
  7.         self.name = name
  8.         self.age = age
  9.         self.email = email
  10.     def to_dict(self):
  11.         return {"Name": self.name, "Age": self.age, "Email": self.email}
  12. # 用一个 wxPython 窗口展示如何导出数据
  13. class MyFrame(wx.Frame):
  14.     def __init__(self, parent, title):
  15.         super().__init__(parent, title=title, size=(300, 200))
  16.         
  17.         self.panel = wx.Panel(self)
  18.         self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
  19.         
  20.         # 创建一些实体类数据
  21.         self.person_list = [
  22.             Person("Alice", 30, "alice@example.com"),
  23.             Person("Bob", 25, "bob@example.com"),
  24.             Person("Charlie", 35, "charlie@example.com")
  25.         ]
  26.         
  27.         self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
  28.         self.Show()
  29.     def export_to_excel(self, event):
  30.         # 将实体类列表转换为字典列表
  31.         data = [person.to_dict() for person in self.person_list]
  32.         
  33.         # 创建 Excel 工作簿和工作表
  34.         wb = Workbook()
  35.         ws = wb.active
  36.         ws.title = "People Data"
  37.         
  38.         # 设置标题行并加粗背景色
  39.         titles = ["Name", "Age", "Email"]
  40.         ws.append(titles)
  41.         
  42.         # 设置标题样式:加粗和背景色
  43.         title_font = Font(bold=True)
  44.         title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")  # 黄色背景
  45.         for cell in ws[1]:
  46.             cell.font = title_font
  47.             cell.fill = title_fill
  48.         
  49.         # 填充数据
  50.         for person in data:
  51.             ws.append([person["Name"], person["Age"], person["Email"]])
  52.         
  53.         # 保存到文件
  54.         wb.save("exported_data_with_styles.xlsx")
  55.         
  56.         wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)
  57. # 启动 wxPython 应用
  58. app = wx.App(False)
  59. frame = MyFrame(None, "导出实体类数据到 Excel")
  60. app.MainLoop()
复制代码
Excel 在 openpyxl 中可以设置自适应列宽或者指定具体的列宽,乃至可以设置框架(边框样式)。
固然 openpyxl 本身并没有直接提供“自动调整列宽”的功能,但我们可以通过遍历列中的所有单位格来计算每列的最大宽度,然后动态调整列宽。
调整后的代码如下所示。
  1. import wx
  2. from openpyxl import Workbook
  3. from openpyxl.styles import Font, PatternFill, Border, Side
  4. # 假设这是你的实体类
  5. class Person:
  6.     def __init__(self, name, age, email):
  7.         self.name = name
  8.         self.age = age
  9.         self.email = email
  10.     def to_dict(self):
  11.         return {"Name": self.name, "Age": self.age, "Email": self.email}
  12. # 用一个 wxPython 窗口展示如何导出数据
  13. class MyFrame(wx.Frame):
  14.     def __init__(self, parent, title):
  15.         super().__init__(parent, title=title, size=(300, 200))
  16.         
  17.         self.panel = wx.Panel(self)
  18.         self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
  19.         
  20.         # 创建一些实体类数据
  21.         self.person_list = [
  22.             Person("Alice", 30, "alice@example.com"),
  23.             Person("Bob", 25, "bob@example.com"),
  24.             Person("Charlie", 35, "charlie@example.com")
  25.         ]
  26.         
  27.         self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
  28.         self.Show()
  29.     def export_to_excel(self, event):
  30.         # 将实体类列表转换为字典列表
  31.         data = [person.to_dict() for person in self.person_list]
  32.         
  33.         # 创建 Excel 工作簿和工作表
  34.         wb = Workbook()
  35.         ws = wb.active
  36.         ws.title = "People Data"
  37.         
  38.         # 设置标题行并加粗背景色
  39.         titles = ["Name", "Age", "Email"]
  40.         ws.append(titles)
  41.         
  42.         # 设置标题样式:加粗和背景色
  43.         title_font = Font(bold=True)
  44.         title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")  # 黄色背景
  45.         for cell in ws[1]:
  46.             cell.font = title_font
  47.             cell.fill = title_fill
  48.         
  49.         # 填充数据
  50.         for person in data:
  51.             ws.append([person["Name"], person["Age"], person["Email"]])
  52.         
  53.         # 设置列宽(手动指定或根据内容自适应)
  54.         # 自动调整列宽
  55.         for col in ws.columns:
  56.             max_length = 0
  57.             column = col[0].column_letter  # 获取列字母
  58.             for cell in col:
  59.                 try:
  60.                     if len(str(cell.value)) > max_length:
  61.                         max_length = len(cell.value)
  62.                 except:
  63.                     pass
  64.             adjusted_width = (max_length + 2)
  65.             ws.column_dimensions[column].width = adjusted_width
  66.         
  67.         # 设置框架(边框)
  68.         border = Border(
  69.             left=Side(border_),
  70.             right=Side(border_),
  71.             top=Side(border_),
  72.             bottom=Side(border_)
  73.         )
  74.         for row in ws.iter_rows():
  75.             for cell in row:
  76.                 cell.border = border
  77.         
  78.         # 保存到文件
  79.         wb.save("exported_data_with_styles_and_borders.xlsx")
  80.         
  81.         wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)
  82. # 启动 wxPython 应用
  83. app = wx.App(False)
  84. frame = MyFrame(None, "导出实体类数据到 Excel")
  85. app.MainLoop()
复制代码
点击“导出到Excel”按钮后,程序将天生一个包罗:

  • 自动调整列宽的 Excel 文件;
  • 每个单位格的边框;
  • 标题行加粗并带黄色背景色的 Excel 文件。
为了实现一个通用的导出函数,根据 display_columns 和 column_mapping 设置导出的字段,并映射标题名称,你可以设计一个灵活的函数,接收这些参数并根据需要导出数据到 Excel。

  • display_columns:一个字符串,指定需要导出的字段(如 name,age,email)。
  • column_mapping:一个字典,指定字段到显示名称的映射。
  • list:包罗实体类数据的列表,每个实体类需要提供 to_dict() 方法,将数据转换为字典格式。
  • filename:保存的文件名。
  1. import wx
  2. from openpyxl import Workbook
  3. from openpyxl.styles import Font, PatternFill, Border, Side
  4. def export_to_excel(list_data, display_columns, column_mapping, filename):
  5.     # 解析 display_columns 为列表
  6.     display_columns = display_columns.split(',')
  7.    
  8.     # 获取映射后的标题
  9.     headers = [column_mapping.get(col, col) for col in display_columns]
  10.     # 创建 Excel 工作簿和工作表
  11.     wb = Workbook()
  12.     ws = wb.active
  13.     ws.title = "Data"
  14.     # 设置标题行并加粗背景色
  15.     ws.append(headers)
  16.     title_font = Font(bold=True)
  17.     title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")  # 黄色背景
  18.     for cell in ws[1]:
  19.         cell.font = title_font
  20.         cell.fill = title_fill
  21.     # 填充数据
  22.     for data_item in list_data:
  23.         row = [data_item.get(col) for col in display_columns]
  24.         ws.append(row)
  25.     # 设置列宽(自动调整)
  26.     for col in ws.columns:
  27.         max_length = 0
  28.         column = col[0].column_letter  # 获取列字母
  29.         for cell in col:
  30.             try:
  31.                 if len(str(cell.value)) > max_length:
  32.                     max_length = len(cell.value)
  33.             except:
  34.                 pass
  35.         adjusted_width = (max_length + 2)
  36.         ws.column_dimensions[column].width = adjusted_width
  37.     # 设置框架(边框)
  38.     border = Border(
  39.         left=Side(border_),
  40.         right=Side(border_),
  41.         top=Side(border_),
  42.         bottom=Side(border_)
  43.     )
  44.     for row in ws.iter_rows():
  45.         for cell in row:
  46.             cell.border = border
  47.     # 保存到文件
  48.     wb.save(filename)
  49.     return f"导出成功!文件已保存为 {filename}"
复制代码
调用代码如下所示
  1.     def export(self, event):
  2.         display_columns = "name,age,email"  # 需要导出的字段
  3.         column_mapping = {
  4.             "age": "年龄",
  5.             "email": "电子邮箱",
  6.             "name": "显示名称"
  7.         }
  8.         filename = "exported_data.xlsx"  # 保存的文件名
  9.         result = export_to_excel(
  10.             [person.to_dict() for person in self.person_list],
  11.             display_columns,
  12.             column_mapping,
  13.             filename
  14.         )
  15.         wx.MessageBox(result, "信息", wx.OK | wx.ICON_INFORMATION)
复制代码
你只需调用 export_to_excel 函数并传递数据、要导出的字段(display_columns)、字段映射(column_mapping)和保存的文件名(filename)。它会天生一个 Excel 文件,并按要求设置样式。
在 openpyxl 中,自动调整列宽是通过检查列中内容的最大长度来实现的。假如你发现某一列(例如“年龄”列)的宽度过窄,大概是因为该列中的数据(例如数字)被视为较短的字符串,导致列宽过小。
为了办理这个问题,您可以通过设置列宽时为数字列提供额外的宽度赔偿,或者通过在计算列宽时增加一个常量来确保列宽更符合。
  1.     # 设置列宽(自动调整)
  2.     for col in ws.columns:
  3.         max_length = 0
  4.         column = col[0].column_letter  # 获取列字母
  5.         for cell in col:
  6.             try:
  7.                 if cell.value:
  8.                     cell_value = str(cell.value)
  9.                     # 增加补偿宽度:如果是数字列,增加额外宽度
  10.                     if isinstance(cell.value, (int, float)):
  11.                         max_length = max(max_length, len(cell_value) + 2)  # 数字列增加 2 的宽度
  12.                     else:
  13.                         max_length = max(max_length, len(cell_value))
  14.             except:
  15.                 pass
  16.         adjusted_width = (max_length + 2)  # 留出一些额外的空间
  17.         ws.column_dimensions[column].width = max(adjusted_width, 12)  # 设置最小宽度为 12
复制代码

  • 列宽赔偿:对于数字列(如 age 列),在计算最大长度时增加一个 +2 的赔偿。这将确保数字列的列宽充足显示数字值。
  • 最小列宽:为了制止列过窄,我设置了 max(adjusted_width, 12),确保列宽至少为 12。假如计算出的列宽小于 12,将强制设置为 12。
  • 自动列宽:自动计算每列的最大长度,并为每列分配符合的宽度。
假如我们需要再现实业务中导出数据,如对于用户信息,实体类为UserDto,那么我们需要在导出数据之前,将 UserDto 类型的对象转换为字典格式。
在每个 DTO 对象中,添加一个 to_dict 方法,用于将对象的属性转换为字典。to_dict 方法可以返回一个字典,其中每个键是类属性的名称,每个值是对应的属性值。
不外我的跨平台框架中的UserDto对象是与Pydantic模子的,因此它可以通过函数 model_dump  举行通用处置惩罚为字典对象。
使用 model_dump 方法可以很方便地将 Python 类对象(特别是 Pydantic 模子或者具备 model_dump 方法的类)转换为字典。假如你正在使用 Pydantic 或者使用了某些自定义实现了 model_dump 方法的类,可以直接调用该方法来完成对象到字典的转换。
假设你有一个 UserDto 类,它是一个 Pydantic 模子:
  1. from pydantic import BaseModel
  2. class UserDto(BaseModel):
  3.     name: str
  4.     age: int
  5.     email: str
  6. # 创建一个 UserDto 实例
  7. user = UserDto(name="Alice", age=30, email="alice@example.com")
  8. # 使用 model_dump 将对象转换为字典
  9. user_dict = user.model_dump()
  10. print(user_dict)
复制代码
在这个例子中,model_dump 会自动将 Pydantic 模子实例转换为字典,所有字段(即类的属性)都会成为字典的键,属性值成为字典的值。
假如你有嵌套的 Pydantic 模子,model_dump 会自动递归地将嵌套模子转换为字典。假如你的项目中使用了 Pydantic,这种方法将非常简便高效。
3、在项目列表基类中增加导出功能

通过上面的封装测试,我们可以把导出Excel的功能做的很不错了,因此把它整合到列表基类里面,通过基类界面中增加一个导出按钮即可实现所有业务模块的数据导出,不用每个页面都实现,简化了操作。

添加按钮采用通用辅助函数参加按钮及图标,并增加导出的处置惩罚函数,如下代码所示。
  1.   btn_export = ControlUtil.create_button(
  2.       pane, "导出Excel", "xls", handler=self.OnExport, is_async=True
  3.   )
复制代码
 
OnExport函数的实现如下所示。
  1.     async def OnExport(self, event: wx.Event) -> None:
  2.         """导出数据"""
  3.         # 检查数据是否是一个 Pydantic 实体
  4.         export_list = []
  5.         for item in self.data:
  6.             if hasattr(item, "model_dump"):
  7.                 export_item = item.model_dump()
  8.                 export_list.append(export_item)
  9.             else:
  10.                 export_list.append(item)
  11.         # print(export_list)
  12.         filename = FileDialogUtil.save_excel(self)
  13.         if not filename:
  14.             return
  15.         result = ExcelUtil.export_to_excel(
  16.             export_list, self.display_columns, self.column_mapping, filename
  17.         )
  18.         if result:
  19.             if (
  20.                 MessageUtil.show_confirm(self, "导出成功,是否打开文件?", "导出成功")
  21.                 == wx.ID_YES
  22.             ):
  23.                 ExcelUtil.open_file(filename)
  24.         else:
  25.             MessageUtil.show_error(self, "导出失败")
复制代码
在MacOS上弹出导出提示,如下所示。

确认后提示,是否打开文件如下。

导出的文件打开后,可以看到效果如下所示

 
4、文件的打开方式和跨平台打开实现

留意,不同平台打开文件举行查看,操作方式有所不同。
假如你想用默认应用(如 Excel 或 Numbers)直接打开 .xls 文件,你可以通过 Python 的 subprocess 模块调用 macOS 上的应用程序来打开文件。
在 macOS 中,open 命令可以用来打开任何文件。假如你希望在默认的应用程序中打开 .xls 文件(例如 Excel 或 Numbers),可以使用如下方法:
  1. import subprocess
  2. # 打开 .xls 文件
  3. subprocess.run(["open", "your_file.xls"])
复制代码
macOS 支持通过 os 模块调用系统命令来打开文件。可以通过 os.system() 或 subprocess.run() 来调用 open 命令,在 macOS 上打开文件。
  1. import os
  2. # 打开 .xls 文件
  3. os.system("open your_file.xls")
复制代码
通过 os.system("open your_file.xls") 或 subprocess.run(["open", "your_file.xls"]),你可以在 macOS 上使用默认的应用程序(如 Excel 或 Numbers)打开 .xls 文件。这些方法非常简单且不需要依赖外部库。
os.startfile() 是 Windows 系统中的一个特定方法,用于打开文件并在关联的默认应用程序中显示它。然而,os.startfile() 在 macOSLinux 系统中不可用。因此,在 macOS 上使用该方法会导致错误。
为了使代码在不同平台上都能工作,您可以编写一个条件判定,区分操作系统并使用符合的命令来打开文件。
  1. import os
  2. import subprocess
  3. import platform
  4. def open_file(file_path):
  5.     system = platform.system()
  6.    
  7.     if system == "Darwin":  # macOS
  8.         subprocess.run(["open", file_path])
  9.     elif system == "Windows":
  10.         os.startfile(file_path)
  11.     elif system == "Linux":
  12.         subprocess.run(["xdg-open", file_path])
  13.     else:
  14.         raise NotImplementedError(f"Unsupported operating system: {system}")
  15. # 示例调用
  16. open_file("your_file.xls")
复制代码
说明:


  • macOS (Darwin):使用 open 命令。
  • Windows:使用 os.startfile(),这是 Windows 特有的方法。
  • Linux:使用 xdg-open 命令,实用于大多数 Linux 发行版。
对于跨平台执行系统命令,保举使用 subprocess 模块,它提供了更强大的功能,并且更灵活和安全。subprocess.run() 方法是一个更通用的替代方案。
因此结合通用的导出Excel和打开文件,就可以实现Excel文件的导出打开操作了,各个业务列表模块度是基于列表基础页面的,因此自动具有导出的功能,当然,我们也可以根据一些条件举行判定是否使用导出按钮即可。
列表界面继承基类,从而可以大幅度的使用相应的规则和实现。
 

 如对于两个例子窗体:系统类型定义,客户信息,其中传如对应的DTO信息和参数即可。


子类继承基类列表页面,并传入对应的参数即可具体化相关的业务功能了。

以上就是根据抽象继承的方式,对不同业务模块的通用导出Excel文件功能,以及跨平台的打开处置惩罚方式的实现。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表