EXCEL根据类别分页预览或者直接生成PDF

vbscript 复制代码
Sub PrintByCategoryWithOptions_SilentMode()
    Dim ws As Worksheet
    Dim dict As Object
    Dim key As Variant
    Dim lastRow As Long, i As Long
    Dim categoryColumn As Long
    Dim counter As Long
    Dim response As VbMsgBoxResult
    Dim outputMode As String
    Dim savePath As String
    Dim pdfFileName As String
    
    ' *************** 用户可修改参数 ***************
    Set ws = ThisWorkbook.Sheets("退款明细")  ' 工作表名
    categoryColumn = 3                        ' 分类列号(C列=3)
    Const titleRows As Long = 4               ' 标题行数(1-4行)
    Const lastCol As String = "J"             ' 最后一列字母
    ' *********************************************
    
    lastRow = ws.Cells(ws.Rows.Count, categoryColumn).End(xlUp).Row
    
    ' 创建字典存储分类信息
    Set dict = CreateObject("Scripting.Dictionary")
    
    ' 扫描所有分类并记录行范围
    Dim currentCategory As String
    Dim startRow As Long, endRow As Long
    Dim isNewCategory As Boolean
    
    startRow = titleRows + 1
    currentCategory = CStr(ws.Cells(startRow, categoryColumn).Value)
    
    For i = startRow To lastRow
        isNewCategory = (CStr(ws.Cells(i, categoryColumn).Value) <> currentCategory)
        
        If isNewCategory Or i = lastRow Then
            endRow = IIf(i = lastRow And Not isNewCategory, i, i - 1)
            
            If Not dict.Exists(currentCategory) And currentCategory <> "" Then
                dict.Add currentCategory, Array(startRow, endRow)
            End If
            
            If isNewCategory Then
                currentCategory = CStr(ws.Cells(i, categoryColumn).Value)
                startRow = i
            End If
        End If
    Next i
    
    ' 增强的输出模式选择
    response = Application.InputBox( _
        "请选择操作方式:" & vbCrLf & vbCrLf & _
        "1 - 打印预览(逐个查看)" & vbCrLf & _
        "2 - 生成PDF(逐个提示)" & vbCrLf & _
        "3 - 批量生成PDF(无提示)" & vbCrLf & vbCrLf & _
        "请输入数字选项 (1-3):", _
        "输出模式选择", "3", Type:=1)
    
    ' 处理用户选择
    If response = False Then Exit Sub  ' 用户取消
    
    Select Case response
        Case 1: outputMode = "PREVIEW"
        Case 2: outputMode = "PDF_PROMPT"
        Case 3: outputMode = "PDF_SILENT"
        Case Else
            MsgBox "无效选项,操作已取消", vbExclamation
            Exit Sub
    End Select
    
    ' PDF模式获取保存路径
    If outputMode Like "PDF*" Then
        savePath = BrowseForFolder("选择PDF保存位置")
        If savePath = "" Then Exit Sub
    End If
    
    ' 关闭屏幕更新加快速度
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.DisplayAlerts = False
    
    ' 备份原始设置
    Dim originalPrintArea As String
    originalPrintArea = ws.PageSetup.PrintArea
    
    ' 记录开始时间
    Dim startTime As Double
    startTime = Timer
    
    ' 按顺序处理每个分类
    Dim categories() As Variant
    categories = dict.keys
    
    For counter = 0 To dict.Count - 1
        key = categories(counter)
        Dim rowRange() As Variant
        rowRange = dict(key)
        startRow = rowRange(0)
        endRow = rowRange(1)
        
        ' 计算打印区域
        Dim printArea As String
        printArea = "$A$1:$" & lastCol & "$" & endRow
        
        ' 隐藏非当前分类的行
        HideNonCurrentRows ws, startRow, endRow, titleRows, lastRow
        
        ' 设置打印区域
        ws.PageSetup.PrintArea = printArea
        
        ' 根据模式执行操作
        Select Case outputMode
            Case "PREVIEW"
                ' 预览前提示信息
                Dim previewMsg As String
                previewMsg = "正在预览类别: " & key & vbCrLf & _
                             "(" & (counter + 1) & "/" & dict.Count & ")" & vbCrLf & _
                             "数据行范围: " & startRow & " - " & endRow & vbCrLf & _
                             "打印区域: A1:" & lastCol & endRow
                
                MsgBox previewMsg, vbInformation, "准备预览"
                ws.PrintPreview
                
                ' 预览后询问
                If MsgBox("类别: " & key & " 预览完成" & vbCrLf & _
                          "是否继续下一个类别?", vbYesNo + vbQuestion) = vbNo Then Exit For
                
            Case "PDF_PROMPT"
                ' 生成前提示信息
                Dim pdfMsg As String
                pdfMsg = "正在生成: " & key & vbCrLf & _
                         "(" & (counter + 1) & "/" & dict.Count & ")" & vbCrLf & _
                         "数据行范围: " & startRow & " - " & endRow
                
                MsgBox pdfMsg, vbInformation, "PDF生成中"
                
                ' 生成PDF文件
                pdfFileName = CleanFileName(key & "") & ".pdf"
                ws.ExportAsFixedFormat _
                    Type:=xlTypePDF, _
                    Filename:=savePath & pdfFileName, _
                    Quality:=xlQualityStandard, _
                    IncludeDocProperties:=True, _
                    IgnorePrintAreas:=False
                
            Case "PDF_SILENT"
                ' 静默模式 - 仅更新状态栏
                Application.StatusBar = "正在批量生成PDF (" & (counter + 1) & "/" & dict.Count & "): " & key
                
                ' 生成PDF文件
                pdfFileName = CleanFileName(key & "") & ".pdf"
                ws.ExportAsFixedFormat _
                    Type:=xlTypePDF, _
                    Filename:=savePath & pdfFileName, _
                    Quality:=xlQualityStandard, _
                    IncludeDocProperties:=True, _
                    IgnorePrintAreas:=False
        End Select
        
        ' 恢复所有行的可见性
        ws.Rows.Hidden = False
    Next counter
    
    ' 计算耗时
    Dim elapsedTime As Double
    elapsedTime = Round(Timer - startTime, 2)
    
    ' 恢复原始设置
    ws.PageSetup.PrintArea = originalPrintArea
    ws.Rows.Hidden = False
    Application.StatusBar = False
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.DisplayAlerts = True
    
    ' 完成提示
    Dim msg As String
    msg = "操作完成!" & vbCrLf & "共处理 " & dict.Count & " 个类别" & vbCrLf & _
          "耗时: " & elapsedTime & " 秒"
    
    If outputMode Like "PDF*" Then
        msg = msg & vbCrLf & "PDF保存到: " & savePath
        
        ' 完成后打开保存文件夹
        If MsgBox(msg & vbCrLf & vbCrLf & "是否打开保存文件夹?", vbQuestion + vbYesNo, "操作完成") = vbYes Then
            Shell "explorer.exe """ & savePath & """", vbNormalFocus
        End If
    Else
        MsgBox msg, vbInformation, "报告"
    End If
End Sub

' 辅助函数:隐藏非当前分类的行
Sub HideNonCurrentRows(ws As Worksheet, startRow As Long, endRow As Long, titleRows As Long, lastRow As Long)
    ws.Rows.Hidden = False
    If titleRows + 1 < startRow Then
        ws.Rows(titleRows + 1 & ":" & startRow - 1).Hidden = True
    End If
    If endRow < lastRow Then
        ws.Rows(endRow + 1 & ":" & lastRow).Hidden = True
    End If
End Sub

Function CleanFileName(str As String) As String
    Dim illegalChars As String
    illegalChars = "\/:*?""<>|"
    CleanFileName = str
    For i = 1 To Len(illegalChars)
        CleanFileName = Replace(CleanFileName, Mid(illegalChars, i, 1), "_")
    Next i
End Function

Function BrowseForFolder(title As String) As String
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = title
        If .Show <> -1 Then Exit Function
        BrowseForFolder = .SelectedItems(1)
        If Right(BrowseForFolder, 1) <> "\" Then BrowseForFolder = BrowseForFolder & "\"
    End With
End Function

使用方法:运行宏,粘贴代码。

请选择操作方式:

1 - 打印预览(逐个查看)

2 - 生成PDF(逐个提示)

3 - 批量生成PDF(无提示)

请输入数字选项 (1-3):

优势:

  1. 高效处理

    • 静默模式下可一次性处理数百个分类
    • 无需人工干预,适合批量操作
  2. 灵活选择

    • 根据需求选择不同详细程度的模式
    • 调试时用预览模式,日常操作用静默模式
  3. 用户体验

    • 完成后可直接打开保存文件夹
    • 显示处理时间便于性能评估
    • 状态栏进度反馈让用户了解运行状态
相关推荐
小吴编程之路21 小时前
MySQL 索引核心特性深度解析:从底层原理到实操应用
数据库·mysql
~莫子1 天前
MySQL集群技术
数据库·mysql
凤山老林1 天前
SpringBoot 使用 H2 文本数据库构建轻量级应用
java·数据库·spring boot·后端
就不掉头发1 天前
Linux与数据库进阶
数据库
与衫1 天前
Gudu SQL Omni 技术深度解析
数据库·sql
咖啡の猫1 天前
Redis桌面客户端
数据库·redis·缓存
oradh1 天前
Oracle 11g数据库软件和数据库静默安装
数据库·oracle
what丶k1 天前
如何保证 Redis 与 MySQL 数据一致性?后端必备实践指南
数据库·redis·mysql
_半夏曲1 天前
PostgreSQL 13、14、15 区别
数据库·postgresql
把你毕设抢过来1 天前
基于Spring Boot的社区智慧养老监护管理平台(源码+文档)
数据库·spring boot·后端