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. 用户体验

    • 完成后可直接打开保存文件夹
    • 显示处理时间便于性能评估
    • 状态栏进度反馈让用户了解运行状态
相关推荐
q***829129 分钟前
如何使用C#与SQL Server数据库进行交互
数据库·c#·交互
盖世英雄酱581361 小时前
commit 成功为什么数据只更新了部分?
java·数据库·后端
煎蛋学姐2 小时前
SSM网上旅游订票服务系统10r27(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·ssm 框架·网上旅游订票系统·旅游服务数字化
海南java第二人2 小时前
数据库范式详解:从冗余到规范的升华之旅
数据库·oracle·ffmpeg
hyx0412193 小时前
mysql第5次作业---hyx
数据库·mysql
Daniel大人3 小时前
关于sqlite
数据库·sqlite
nsjqj3 小时前
MySQL数据库:表的增删改查 [CRUD](进阶)【一】
数据库·mysql
她说..4 小时前
Redis实现未读消息计数
java·数据库·redis·缓存
xiayehuimou4 小时前
Redis核心技术与实战指南
数据库·redis·缓存
Yeats_Liao4 小时前
时序数据库系列(八):InfluxDB配合Grafana可视化
数据库·后端·grafana·时序数据库