兜兜零元 发表于 2024-12-9 21:15:48

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

在 Python 中使用 wxPython 导出实体类列表数据到 Excel,通常可以借助 openpyxl 或 pandas 库来实现。本篇随笔由浅入深,逐步介绍导出Excel文件的操作,然后结合跨平台项目标实现,根据抽象继承的方式,对不同业务模块的通用导出Excel文件功能,以及跨平台的打开处置惩罚方式的实现举行介绍。
以下是一个基本示例,展示如何将实体类的列表数据导出到 Excel 文件。
1、使用pandas 库导出Excel

import wx
import pandas as pd

# 假设这是你的实体类
class Person:
    def __init__(self, name, age, email):
      self.name = name
      self.age = age
      self.email = email

    def to_dict(self):
      return {"Name": self.name, "Age": self.age, "Email": self.email}

# 用一个 wxPython 窗口展示如何导出数据
class MyFrame(wx.Frame):
    def __init__(self, parent, title):
      super().__init__(parent, title=title, size=(300, 200))
      
      self.panel = wx.Panel(self)
      self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
      
      # 创建一些实体类数据
      self.person_list = [
            Person("Alice", 30, "alice@example.com"),
            Person("Bob", 25, "bob@example.com"),
            Person("Charlie", 35, "charlie@example.com")
      ]
      
      self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
      self.Show()

    def export_to_excel(self, event):
      # 将实体类列表转换为字典列表
      data =
      
      # 使用 pandas 导出到 Excel
      df = pd.DataFrame(data)
      df.to_excel("exported_data.xlsx", index=False)
      
      wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)

# 启动 wxPython 应用
app = wx.App(False)
frame = MyFrame(None, "导出实体类数据到 Excel")
app.MainLoop()实体类 (Person):包罗一些字段,如 name、age 和 email,并定义了 to_dict 方法,将实体对象转换为字典格式,以便更轻易处置惩罚。
export_to_excel:这个方法将实体类列表转换为字典列表,使用 pandas 库将数据导出为 Excel 文件。
假如你需要更多的功能(如自定义 Excel 格式,单位格样式等),可以进一步扩展 openpyxl 或 xlsxwriter 来提供更复杂的导出选项。
 
2、使用 openpyxl 库导出Excel

要在 Excel 导出时为标题加粗并设置背景色,你可以使用 openpyxl 库,它提供了丰富的功能来设置单位格样式(如字体、背景色等)。
以下是一个更新的示例,演示如何在导出数据时,设置 Excel 标题行的加粗和背景色。
import wx
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill

# 假设这是你的实体类
class Person:
    def __init__(self, name, age, email):
      self.name = name
      self.age = age
      self.email = email

    def to_dict(self):
      return {"Name": self.name, "Age": self.age, "Email": self.email}

# 用一个 wxPython 窗口展示如何导出数据
class MyFrame(wx.Frame):
    def __init__(self, parent, title):
      super().__init__(parent, title=title, size=(300, 200))
      
      self.panel = wx.Panel(self)
      self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
      
      # 创建一些实体类数据
      self.person_list = [
            Person("Alice", 30, "alice@example.com"),
            Person("Bob", 25, "bob@example.com"),
            Person("Charlie", 35, "charlie@example.com")
      ]
      
      self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
      self.Show()

    def export_to_excel(self, event):
      # 将实体类列表转换为字典列表
      data =
      
      # 创建 Excel 工作簿和工作表
      wb = Workbook()
      ws = wb.active
      ws.title = "People Data"
      
      # 设置标题行并加粗背景色
      titles = ["Name", "Age", "Email"]
      ws.append(titles)
      
      # 设置标题样式:加粗和背景色
      title_font = Font(bold=True)
      title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")# 黄色背景
      for cell in ws:
            cell.font = title_font
            cell.fill = title_fill
      
      # 填充数据
      for person in data:
            ws.append(, person["Age"], person["Email"]])
      
      # 保存到文件
      wb.save("exported_data_with_styles.xlsx")
      
      wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)

# 启动 wxPython 应用
app = wx.App(False)
frame = MyFrame(None, "导出实体类数据到 Excel")
app.MainLoop()Excel 在 openpyxl 中可以设置自适应列宽或者指定具体的列宽,乃至可以设置框架(边框样式)。
固然 openpyxl 本身并没有直接提供“自动调整列宽”的功能,但我们可以通过遍历列中的所有单位格来计算每列的最大宽度,然后动态调整列宽。
调整后的代码如下所示。
import wx
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Border, Side

# 假设这是你的实体类
class Person:
    def __init__(self, name, age, email):
      self.name = name
      self.age = age
      self.email = email

    def to_dict(self):
      return {"Name": self.name, "Age": self.age, "Email": self.email}

# 用一个 wxPython 窗口展示如何导出数据
class MyFrame(wx.Frame):
    def __init__(self, parent, title):
      super().__init__(parent, title=title, size=(300, 200))
      
      self.panel = wx.Panel(self)
      self.button = wx.Button(self.panel, label="导出到Excel", pos=(50, 50))
      
      # 创建一些实体类数据
      self.person_list = [
            Person("Alice", 30, "alice@example.com"),
            Person("Bob", 25, "bob@example.com"),
            Person("Charlie", 35, "charlie@example.com")
      ]
      
      self.Bind(wx.EVT_BUTTON, self.export_to_excel, self.button)
      self.Show()

    def export_to_excel(self, event):
      # 将实体类列表转换为字典列表
      data =
      
      # 创建 Excel 工作簿和工作表
      wb = Workbook()
      ws = wb.active
      ws.title = "People Data"
      
      # 设置标题行并加粗背景色
      titles = ["Name", "Age", "Email"]
      ws.append(titles)
      
      # 设置标题样式:加粗和背景色
      title_font = Font(bold=True)
      title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")# 黄色背景
      for cell in ws:
            cell.font = title_font
            cell.fill = title_fill
      
      # 填充数据
      for person in data:
            ws.append(, person["Age"], person["Email"]])
      
      # 设置列宽(手动指定或根据内容自适应)
      # 自动调整列宽
      for col in ws.columns:
            max_length = 0
            column = col.column_letter# 获取列字母
            for cell in col:
                try:
                  if len(str(cell.value)) > max_length:
                        max_length = len(cell.value)
                except:
                  pass
            adjusted_width = (max_length + 2)
            ws.column_dimensions.width = adjusted_width
      
      # 设置框架(边框)
      border = Border(
            left=Side(border_),
            right=Side(border_),
            top=Side(border_),
            bottom=Side(border_)
      )
      for row in ws.iter_rows():
            for cell in row:
                cell.border = border
      
      # 保存到文件
      wb.save("exported_data_with_styles_and_borders.xlsx")
      
      wx.MessageBox("导出成功!", "信息", wx.OK | wx.ICON_INFORMATION)

# 启动 wxPython 应用
app = wx.App(False)
frame = MyFrame(None, "导出实体类数据到 Excel")
app.MainLoop()点击“导出到Excel”按钮后,程序将天生一个包罗:

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

[*]display_columns:一个字符串,指定需要导出的字段(如 name,age,email)。
[*]column_mapping:一个字典,指定字段到显示名称的映射。
[*]list:包罗实体类数据的列表,每个实体类需要提供 to_dict() 方法,将数据转换为字典格式。
[*]filename:保存的文件名。
import wx
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Border, Side

def export_to_excel(list_data, display_columns, column_mapping, filename):
    # 解析 display_columns 为列表
    display_columns = display_columns.split(',')
   
    # 获取映射后的标题
    headers =

    # 创建 Excel 工作簿和工作表
    wb = Workbook()
    ws = wb.active
    ws.title = "Data"

    # 设置标题行并加粗背景色
    ws.append(headers)
    title_font = Font(bold=True)
    title_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")# 黄色背景
    for cell in ws:
      cell.font = title_font
      cell.fill = title_fill

    # 填充数据
    for data_item in list_data:
      row =
      ws.append(row)

    # 设置列宽(自动调整)
    for col in ws.columns:
      max_length = 0
      column = col.column_letter# 获取列字母
      for cell in col:
            try:
                if len(str(cell.value)) > max_length:
                  max_length = len(cell.value)
            except:
                pass
      adjusted_width = (max_length + 2)
      ws.column_dimensions.width = adjusted_width

    # 设置框架(边框)
    border = Border(
      left=Side(border_),
      right=Side(border_),
      top=Side(border_),
      bottom=Side(border_)
    )
    for row in ws.iter_rows():
      for cell in row:
            cell.border = border

    # 保存到文件
    wb.save(filename)
    return f"导出成功!文件已保存为 {filename}"调用代码如下所示
    def export(self, event):
      display_columns = "name,age,email"# 需要导出的字段
      column_mapping = {
            "age": "年龄",
            "email": "电子邮箱",
            "name": "显示名称"
      }
      filename = "exported_data.xlsx"# 保存的文件名
      result = export_to_excel(
            ,
            display_columns,
            column_mapping,
            filename
      )
      wx.MessageBox(result, "信息", wx.OK | wx.ICON_INFORMATION)你只需调用 export_to_excel 函数并传递数据、要导出的字段(display_columns)、字段映射(column_mapping)和保存的文件名(filename)。它会天生一个 Excel 文件,并按要求设置样式。
在 openpyxl 中,自动调整列宽是通过检查列中内容的最大长度来实现的。假如你发现某一列(例如“年龄”列)的宽度过窄,大概是因为该列中的数据(例如数字)被视为较短的字符串,导致列宽过小。
为了办理这个问题,您可以通过设置列宽时为数字列提供额外的宽度赔偿,或者通过在计算列宽时增加一个常量来确保列宽更符合。
    # 设置列宽(自动调整)
    for col in ws.columns:
      max_length = 0
      column = col.column_letter# 获取列字母
      for cell in col:
            try:
                if cell.value:
                  cell_value = str(cell.value)
                  # 增加补偿宽度:如果是数字列,增加额外宽度
                  if isinstance(cell.value, (int, float)):
                        max_length = max(max_length, len(cell_value) + 2)# 数字列增加 2 的宽度
                  else:
                        max_length = max(max_length, len(cell_value))
            except:
                pass
      adjusted_width = (max_length + 2)# 留出一些额外的空间
      ws.column_dimensions.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 模子:
from pydantic import BaseModel

class UserDto(BaseModel):
    name: str
    age: int
    email: str

# 创建一个 UserDto 实例
user = UserDto(name="Alice", age=30, email="alice@example.com")

# 使用 model_dump 将对象转换为字典
user_dict = user.model_dump()

print(user_dict)在这个例子中,model_dump 会自动将 Pydantic 模子实例转换为字典,所有字段(即类的属性)都会成为字典的键,属性值成为字典的值。
假如你有嵌套的 Pydantic 模子,model_dump 会自动递归地将嵌套模子转换为字典。假如你的项目中使用了 Pydantic,这种方法将非常简便高效。
3、在项目列表基类中增加导出功能

通过上面的封装测试,我们可以把导出Excel的功能做的很不错了,因此把它整合到列表基类里面,通过基类界面中增加一个导出按钮即可实现所有业务模块的数据导出,不用每个页面都实现,简化了操作。
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209213940104-1987743234.png
添加按钮采用通用辅助函数参加按钮及图标,并增加导出的处置惩罚函数,如下代码所示。
btn_export = ControlUtil.create_button(
      pane, "导出Excel", "xls", handler=self.OnExport, is_async=True

OnExport函数的实现如下所示。
    async def OnExport(self, event: wx.Event) -> None:
      """导出数据"""
      # 检查数据是否是一个 Pydantic 实体
      export_list = []
      for item in self.data:
            if hasattr(item, "model_dump"):
                export_item = item.model_dump()
                export_list.append(export_item)
            else:
                export_list.append(item)

      # print(export_list)

      filename = FileDialogUtil.save_excel(self)
      if not filename:
            return

      result = ExcelUtil.export_to_excel(
            export_list, self.display_columns, self.column_mapping, filename
      )
      if result:
            if (
                MessageUtil.show_confirm(self, "导出成功,是否打开文件?", "导出成功")
                == wx.ID_YES
            ):
                ExcelUtil.open_file(filename)
      else:
            MessageUtil.show_error(self, "导出失败")在MacOS上弹出导出提示,如下所示。
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209214333739-643163497.png
确认后提示,是否打开文件如下。
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209214425972-2113998328.png
导出的文件打开后,可以看到效果如下所示
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209214637956-687573929.png
 
4、文件的打开方式和跨平台打开实现

留意,不同平台打开文件举行查看,操作方式有所不同。
假如你想用默认应用(如 Excel 或 Numbers)直接打开 .xls 文件,你可以通过 Python 的 subprocess 模块调用 macOS 上的应用程序来打开文件。
在 macOS 中,open 命令可以用来打开任何文件。假如你希望在默认的应用程序中打开 .xls 文件(例如 Excel 或 Numbers),可以使用如下方法:
import subprocess

# 打开 .xls 文件
subprocess.run(["open", "your_file.xls"])macOS 支持通过 os 模块调用系统命令来打开文件。可以通过 os.system() 或 subprocess.run() 来调用 open 命令,在 macOS 上打开文件。
import os

# 打开 .xls 文件
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() 在 macOS 和 Linux 系统中不可用。因此,在 macOS 上使用该方法会导致错误。
为了使代码在不同平台上都能工作,您可以编写一个条件判定,区分操作系统并使用符合的命令来打开文件。
import os
import subprocess
import platform

def open_file(file_path):
    system = platform.system()
   
    if system == "Darwin":# macOS
      subprocess.run(["open", file_path])
    elif system == "Windows":
      os.startfile(file_path)
    elif system == "Linux":
      subprocess.run(["xdg-open", file_path])
    else:
      raise NotImplementedError(f"Unsupported operating system: {system}")

# 示例调用
open_file("your_file.xls")说明:


[*]macOS (Darwin):使用 open 命令。
[*]Windows:使用 os.startfile(),这是 Windows 特有的方法。
[*]Linux:使用 xdg-open 命令,实用于大多数 Linux 发行版。
对于跨平台执行系统命令,保举使用 subprocess 模块,它提供了更强大的功能,并且更灵活和安全。subprocess.run() 方法是一个更通用的替代方案。
因此结合通用的导出Excel和打开文件,就可以实现Excel文件的导出打开操作了,各个业务列表模块度是基于列表基础页面的,因此自动具有导出的功能,当然,我们也可以根据一些条件举行判定是否使用导出按钮即可。
列表界面继承基类,从而可以大幅度的使用相应的规则和实现。
 https://img2024.cnblogs.com/blog/8867/202411/8867-20241111124709169-1918843705.png
 如对于两个例子窗体:系统类型定义,客户信息,其中传如对应的DTO信息和参数即可。
https://img2024.cnblogs.com/blog/8867/202411/8867-20241111131058275-415274506.png
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209215957304-858753176.png
子类继承基类列表页面,并传入对应的参数即可具体化相关的业务功能了。
https://img2024.cnblogs.com/blog/8867/202412/8867-20241209220223696-2064530110.png
以上就是根据抽象继承的方式,对不同业务模块的通用导出Excel文件功能,以及跨平台的打开处置惩罚方式的实现。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: WxPython跨平台开发框架之表格数据导出到Excel并打开