鱼C论坛

 找回密码
 立即注册
查看: 33|回复: 1

[小天才解惑] 批量打印表格文件

[复制链接]
发表于 昨天 16:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

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

x
  1. import os
  2. import tkinter as tk
  3. from tkinter import filedialog, messagebox
  4. from openpyxl import load_workbook
  5. import win32com.client
  6. import xlrd
  7. import sys

  8. # 创建 Tk 实例并隐藏主窗口
  9. root = tk.Tk()
  10. root.withdraw()  # 隐藏默认窗口

  11. # 定义全局变量存储勾选框状态
  12. checkbox_vars = {}  # 只需定义一次

  13. def create_checkbutton_command(key, var):
  14.     """闭包工厂函数确保正确绑定变量"""
  15.     def _command():
  16.         pass  # 调试信息已移除
  17.     return _command

  18. # 获取用户选择的文件夹路径
  19. folder_path = filedialog.askdirectory()
  20. if not folder_path:
  21.     messagebox.showerror("错误", "未选择文件夹")
  22.     exit()
  23.    
  24. # 打印选中的文件夹路径(可选)
  25. # print(f"Selected folder path: {folder_path}")

  26. # 搜索文件夹内的所有 Excel 或 WPS 表格文件
  27. excel_files = []
  28. for root, dirs, files in os.walk(folder_path):
  29.     for file in files:
  30.         if file.endswith((".xlsx", ".xls",".et",".xlsm")):
  31.             excel_files.append(os.path.join(root, file))

  32. if not excel_files:
  33.     messagebox.showinfo("提示", "未找到 Excel 或 WPS 表格文件")
  34.     exit()

  35. # 创建 Tkinter 窗口
  36. window = tk.Tk()
  37. window.title("选择工作表")
  38. window.geometry("800x600")

  39. # 确保没有默认窗口
  40. root = tk.Tk()  # 假设这里无意中创建了默认窗口
  41. root.withdraw()  # 隐藏默认窗口

  42. # 创建滚动区域
  43. canvas = tk.Canvas(window)
  44. scrollbar_y = tk.Scrollbar(window, orient="vertical", command=canvas.yview)
  45. scrollbar_x = tk.Scrollbar(window, orient="horizontal", command=canvas.xview)
  46. scrollable_frame = tk.Frame(canvas)

  47. # 配置滚动区域
  48. scrollable_frame.bind(
  49.     "<Configure>",
  50.     lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
  51. )
  52. canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
  53. canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)

  54. # 添加鼠标滚轮支持
  55. def _on_mousewheel(event):
  56.     try:
  57.         canvas.yview_scroll(int(-1*(event.delta/120)), "units")
  58.     except tk.TclError:
  59.         pass  # 忽略滚动错误
  60.         
  61. canvas.bind_all("<MouseWheel>", _on_mousewheel)

  62. # 布局滚动区域到窗口顶部
  63. canvas.pack(side="top", fill="both", expand=True)
  64. scrollbar_y.pack(side="right", fill="y")
  65. scrollbar_x.pack(side="bottom", fill="x")

  66. # 遍历每个 Excel 文件,获取工作表名称并创建勾选框
  67. for file_path in excel_files:
  68.     # 获取工作表名称
  69.     if file_path.endswith(".xls"):
  70.         try:
  71.             workbook = xlrd.open_workbook(file_path)
  72.             sheet_names = workbook.sheet_names()
  73.         except Exception as e:
  74.             messagebox.showerror("文件错误", f"无法读取 {file_path}\n错误: {str(e)}")
  75.             continue
  76.     else:
  77.         try:
  78.             wb = load_workbook(filename=file_path, read_only=True)
  79.             sheet_names = wb.sheetnames
  80.             wb.close()
  81.         except Exception as e:
  82.             messagebox.showerror("文件错误", f"无法读取 {file_path}\n错误: {str(e)}")
  83.             continue

  84.     # 创建文件分组框
  85.     file_frame = tk.LabelFrame(scrollable_frame, text=os.path.basename(file_path))
  86.     file_frame.pack(fill="x", padx=5, pady=5)

  87.     # 创建全选变量和按钮
  88.     select_all_var = tk.BooleanVar(master=file_frame, value=False)
  89.    
  90.     # 创建全选命令函数(修正全选功能)
  91.     def create_select_all_command(f_path, var, sheet_names):
  92.         """创建全选命令函数"""
  93.         def _command():
  94.             # 获取当前值并取反作为新值
  95.             new_value = var.get()
  96.             # 更新所有工作表的勾选状态
  97.             norm_path = os.path.normpath(f_path).replace("\", "\\\")  # 保留原始路径格式
  98.             for sheet_name in sheet_names:
  99.                 unique_key = f"{norm_path}__SHEET__{sheet_name}"
  100.                 if unique_key in checkbox_vars:
  101.                     checkbox_vars[unique_key].set(new_value)
  102.         return _command

  103.     # 创建全选按钮
  104.     select_all_checkbox = tk.Checkbutton(
  105.         file_frame,
  106.         text="全选",
  107.         variable=select_all_var,
  108.         command=create_select_all_command(file_path, select_all_var, sheet_names),
  109.         anchor="w",
  110.         width=5
  111.     )
  112.     select_all_checkbox.pack(side="left", padx=5, pady=2)

  113.     # 添加全选变量到全局变量字典(使用文件路径作为键)
  114.     checkbox_vars[file_path] = select_all_var

  115.     for sheet_name in sheet_names:
  116.         # 创建唯一标识
  117.         norm_path = os.path.normpath(file_path).replace("\", "\\\")  # 保留原始路径格式
  118.         unique_key = f"{norm_path}__SHEET__{sheet_name}"
  119.         
  120.         # 创建变量和勾选框
  121.         var = tk.BooleanVar(master=file_frame, value=False)
  122.         checkbox_vars[unique_key] = var
  123.         
  124.         # 创建勾选框组件
  125.         checkbox = tk.Checkbutton(
  126.             file_frame,
  127.             text=sheet_name,
  128.             variable=var,  # 确保变量直接关联
  129.             command=create_checkbutton_command(unique_key, var),  # 直接绑定命令
  130.             anchor="w",
  131.             padx=0,  # 移除内边距
  132.         )
  133.         checkbox.config(width=len(sheet_name) + 2)
  134.         checkbox.pack(side="left", padx=0, pady=1)  # 只在x方向有5像素间距

  135.         # 创建打印份数输入框
  136.         copies_var = tk.StringVar(master=file_frame, value="1")
  137.       

  138.         # 创建一个子框架用于精确控制左右边距
  139.         copies_frame = tk.Frame(file_frame)
  140.         copies_frame.pack(side="left")  # 将子框架放置到主容器中

  141.         # 左侧占位标签,宽度为5
  142.         left_spacer = tk.Label(copies_frame, width=1)
  143.         left_spacer.pack(side="left")

  144.         # 输入框放在左侧占位后
  145.         copies_entry = tk.Entry(copies_frame, textvariable=copies_var, width=3)
  146.         copies_entry.pack(side="left")

  147.         # 右侧占位标签,宽度为50
  148.         right_spacer = tk.Label(copies_frame, width=10)
  149.         right_spacer.pack(side="left")

  150.         # 将 copies_var 存入 checkbox_vars 中(使用 unique_key_copies 做唯一标识)
  151.         unique_key_copies = f"{norm_path}__COPIES__{sheet_name}"
  152.         checkbox_vars[unique_key_copies] = copies_var

  153. # 在全局变量字典之后添加打印函数

  154. def print_selected_sheets():
  155.     """处理选中的工作表进行打印"""
  156.     # 获取所有选中的工作表
  157.     selected_sheets = []
  158.     for key, var in checkbox_vars.items():
  159.         if var.get() and '__SHEET__' in key:
  160.             file_path, sheet_name = key.split('__SHEET__')
  161.             unique_key_copies = f"{file_path}__COPIES__{sheet_name}"
  162.             copies_str = checkbox_vars.get(unique_key_copies, tk.StringVar(value="1")).get()
  163.             try:
  164.                 copies = int(copies_str)
  165.             except ValueError:
  166.                 copies = 1
  167.             selected_sheets.append((file_path.replace('\\\\', '\\'), sheet_name, copies))

  168.     if not selected_sheets:
  169.         messagebox.showinfo("提示", "未选择要打印的工作表")
  170.         return

  171.     # 使用Excel进行打印(需要安装Microsoft Office)
  172.     try:
  173.         excel = win32com.client.Dispatch("Excel.Application")
  174.         excel.Visible = False

  175.         for file_path, sheet_name, copies in selected_sheets:
  176.             wb = excel.Workbooks.Open(file_path)
  177.             ws = wb.Sheets(sheet_name)
  178.             for _ in range(copies):
  179.                 ws.PrintOut()
  180.             wb.Close(SaveChanges=False)

  181.         excel.Quit()
  182.         messagebox.showinfo("完成", "打印任务已发送")
  183.     except Exception as e:
  184.         messagebox.showerror("打印错误", f"打印失败: {str(e)}")

  185.     # 打印完成后关闭窗口
  186.     # window.destroy()

  187. def select_all_sheets(select_all):
  188.     """设置所有工作表的勾选状态"""
  189.     for key, var in checkbox_vars.items():
  190.         if '__SHEET__' in key:  # 只处理工作表勾选框
  191.             var.set(select_all)

  192. def on_exit():
  193.     window.destroy()
  194.     sys.exit()

  195. # 创建按钮框架并放在底部
  196. button_frame = tk.Frame(window)
  197. button_frame.pack(side="bottom", fill="x", pady=10)

  198. print_button = tk.Button(button_frame, text="开始打印", command=print_selected_sheets)
  199. print_button.pack(side="left", padx=20)

  200. # 创建并放置 "全部打印" 按钮
  201. tk.Button(
  202.     button_frame,
  203.     text="全部打印",
  204.     command=lambda: select_all_sheets(True)
  205. ).pack(side="left", padx=20)

  206. exit_button = tk.Button(button_frame, text="退出", command=on_exit)
  207. exit_button.pack(side="right", padx=20)

  208. window.protocol("WM_DELETE_WINDOW", on_exit)  # 绑定关闭事件

  209. # 启动 GUI
  210. window.mainloop()
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 16:18 | 显示全部楼层
您的代码有几个问题需要修复。让我为您提供一个修正后的版本:

主要问题:
  • 变量初始化错误
  • 字典使用不正确
  • 全选功能逻辑错误
  • 变量存储方式混乱


修正后的代码:


  1. import os
  2. import tkinter as tk
  3. from tkinter import filedialog, messagebox
  4. from openpyxl import load_workbook
  5. import win32com.client
  6. import xlrd
  7. import sys

  8. # 创建 Tk 实例并隐藏主窗口
  9. root = tk.Tk()
  10. root.withdraw()

  11. # 定义全局变量存储勾选框状态
  12. checkbox_vars = {}  # 存储工作表选择状态
  13. copies_vars = {}    # 存储打印份数

  14. def create_checkbutton_command(key, var):
  15.     """闭包工厂函数确保正确绑定变量"""
  16.     def _command():
  17.         pass
  18.     return _command

  19. # 获取用户选择的文件夹路径
  20. folder_path = filedialog.askdirectory()
  21. if not folder_path:
  22.     messagebox.showerror("错误", "未选择文件夹")
  23.     exit()
  24.    
  25. # 搜索文件夹内的所有 Excel 或 WPS 表格文件
  26. excel_files = []  # 修复:初始化列表
  27. for root_dir, dirs, files in os.walk(folder_path):
  28.     for file in files:
  29.         if file.endswith((".xlsx", ".xls", ".et", ".xlsm")):
  30.             excel_files.append(os.path.join(root_dir, file))

  31. if not excel_files:
  32.     messagebox.showinfo("提示", "未找到 Excel 或 WPS 表格文件")
  33.     exit()

  34. # 创建 Tkinter 窗口
  35. window = tk.Tk()
  36. window.title("选择工作表")
  37. window.geometry("800x600")

  38. # 创建滚动区域
  39. canvas = tk.Canvas(window)
  40. scrollbar_y = tk.Scrollbar(window, orient="vertical", command=canvas.yview)
  41. scrollbar_x = tk.Scrollbar(window, orient="horizontal", command=canvas.xview)
  42. scrollable_frame = tk.Frame(canvas)

  43. # 配置滚动区域
  44. scrollable_frame.bind(
  45.     "<Configure>",
  46.     lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
  47. )
  48. canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
  49. canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)

  50. # 添加鼠标滚轮支持
  51. def _on_mousewheel(event):
  52.     try:
  53.         canvas.yview_scroll(int(-1*(event.delta/120)), "units")
  54.     except tk.TclError:
  55.         pass
  56.         
  57. canvas.bind_all("<MouseWheel>", _on_mousewheel)

  58. # 布局滚动区域到窗口顶部
  59. canvas.pack(side="top", fill="both", expand=True)
  60. scrollbar_y.pack(side="right", fill="y")
  61. scrollbar_x.pack(side="bottom", fill="x")

  62. # 遍历每个 Excel 文件,获取工作表名称并创建勾选框
  63. for file_path in excel_files:
  64.     # 获取工作表名称
  65.     if file_path.endswith(".xls"):
  66.         try:
  67.             workbook = xlrd.open_workbook(file_path)
  68.             sheet_names = workbook.sheet_names()
  69.         except Exception as e:
  70.             messagebox.showerror("文件错误", f"无法读取 {file_path}\n错误: {str(e)}")
  71.             continue
  72.     else:
  73.         try:
  74.             wb = load_workbook(filename=file_path, read_only=True)
  75.             sheet_names = wb.sheetnames
  76.             wb.close()
  77.         except Exception as e:
  78.             messagebox.showerror("文件错误", f"无法读取 {file_path}\n错误: {str(e)}")
  79.             continue

  80.     # 创建文件分组框
  81.     file_frame = tk.LabelFrame(scrollable_frame, text=os.path.basename(file_path))
  82.     file_frame.pack(fill="x", padx=5, pady=5)

  83.     # 创建全选变量和按钮
  84.     select_all_var = tk.BooleanVar(value=False)
  85.    
  86.     def create_select_all_command(f_path, select_var, sheets):
  87.         """创建全选命令函数"""
  88.         def _command():
  89.             new_value = select_var.get()
  90.             norm_path = os.path.normpath(f_path).replace("\", "\\\")
  91.             for sheet in sheets:
  92.                 unique_key = f"{norm_path}__SHEET__{sheet}"
  93.                 if unique_key in checkbox_vars:
  94.                     checkbox_vars[unique_key].set(new_value)
  95.         return _command

  96.     # 创建全选按钮
  97.     select_all_checkbox = tk.Checkbutton(
  98.         file_frame,
  99.         text="全选",
  100.         variable=select_all_var,
  101.         command=create_select_all_command(file_path, select_all_var, sheet_names),
  102.         anchor="w",
  103.         width=5
  104.     )
  105.     select_all_checkbox.pack(side="left", padx=5, pady=2)

  106.     for sheet_name in sheet_names:
  107.         # 创建唯一标识
  108.         norm_path = os.path.normpath(file_path).replace("\", "\\\")
  109.         unique_key = f"{norm_path}__SHEET__{sheet_name}"
  110.         
  111.         # 创建变量和勾选框
  112.         var = tk.BooleanVar(value=False)
  113.         checkbox_vars[unique_key] = var  # 修复:正确存储到字典
  114.         
  115.         # 创建勾选框组件
  116.         checkbox = tk.Checkbutton(
  117.             file_frame,
  118.             text=sheet_name,
  119.             variable=var,
  120.             command=create_checkbutton_command(unique_key, var),
  121.             anchor="w",
  122.             padx=0,
  123.         )
  124.         checkbox.config(width=len(sheet_name) + 2)
  125.         checkbox.pack(side="left", padx=0, pady=1)

  126.         # 创建打印份数输入框
  127.         copies_var = tk.StringVar(value="1")
  128.         unique_key_copies = f"{norm_path}__COPIES__{sheet_name}"
  129.         copies_vars[unique_key_copies] = copies_var  # 修复:正确存储到字典

  130.         # 创建份数输入框架
  131.         copies_frame = tk.Frame(file_frame)
  132.         copies_frame.pack(side="left")

  133.         # 左侧占位标签
  134.         left_spacer = tk.Label(copies_frame, width=1)
  135.         left_spacer.pack(side="left")

  136.         # 输入框
  137.         copies_entry = tk.Entry(copies_frame, textvariable=copies_var, width=3)
  138.         copies_entry.pack(side="left")

  139.         # 右侧占位标签
  140.         right_spacer = tk.Label(copies_frame, width=10)
  141.         right_spacer.pack(side="left")

  142. def print_selected_sheets():
  143.     """处理选中的工作表进行打印"""
  144.     selected_sheets = []  # 修复:初始化列表
  145.     for key, var in checkbox_vars.items():
  146.         if var.get() and '__SHEET__' in key:
  147.             file_path, sheet_name = key.split('__SHEET__')
  148.             unique_key_copies = f"{file_path}__COPIES__{sheet_name}"
  149.             copies_str = copies_vars.get(unique_key_copies, tk.StringVar(value="1")).get()
  150.             try:
  151.                 copies = int(copies_str)
  152.             except ValueError:
  153.                 copies = 1
  154.             selected_sheets.append((file_path.replace('\\\\', '\\'), sheet_name, copies))

  155.     if not selected_sheets:
  156.         messagebox.showinfo("提示", "未选择要打印的工作表")
  157.         return

  158.     # 使用Excel进行打印
  159.     try:
  160.         excel = win32com.client.Dispatch("Excel.Application")
  161.         excel.Visible = False

  162.         for file_path, sheet_name, copies in selected_sheets:
  163.             wb = excel.Workbooks.Open(file_path)
  164.             ws = wb.Sheets(sheet_name)
  165.             for _ in range(copies):
  166.                 ws.PrintOut()
  167.             wb.Close(SaveChanges=False)

  168.         excel.Quit()
  169.         messagebox.showinfo("完成", "打印任务已发送")
  170.     except Exception as e:
  171.         messagebox.showerror("打印错误", f"打印失败: {str(e)}")

  172. def select_all_sheets(select_all):
  173.     """设置所有工作表的勾选状态"""
  174.     for key, var in checkbox_vars.items():
  175.         if '__SHEET__' in key:
  176.             var.set(select_all)

  177. def on_exit():
  178.     window.destroy()
  179.     sys.exit()

  180. # 创建按钮框架
  181. button_frame = tk.Frame(window)
  182. button_frame.pack(side="bottom", fill="x", pady=10)

  183. print_button = tk.Button(button_frame, text="开始打印", command=print_selected_sheets)
  184. print_button.pack(side="left", padx=20)

  185. tk.Button(
  186.     button_frame,
  187.     text="全部打印",
  188.     command=lambda: select_all_sheets(True)
  189. ).pack(side="left", padx=20)

  190. exit_button = tk.Button(button_frame, text="退出", command=on_exit)
  191. exit_button.pack(side="right", padx=20)

  192. window.protocol("WM_DELETE_WINDOW", on_exit)

  193. # 启动 GUI
  194. window.mainloop()
复制代码


主要修复:
  • 初始化了 excel_filesselected_sheets 列表
  • 正确使用字典存储变量,而不是重新赋值
  • 分离了工作表选择和打印份数的存储
  • 修复了全选功能的逻辑
  • 避免了变量名冲突


现在代码应该可以正常运行了!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-10-27 00:52

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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