如何“强制”Excel正确计算分页符?

时间:2016-04-25 14:44:26

标签: excel vba excel-vba

我应该将一些大型数据范围从Excel导出到Powerpoint,每张幻灯片一页,当然我应该处理分页符以避免“孤立”行或列。

我试图通过读取HPageBreaks.Count和VPageBreaks.Count来检查具有给定缩放的垂直和水平页面数,然后手动定义每个中断的位置。我们的想法是在每个页面上具有大致相同的宽度和高度。

当我逐步调试我的代码时,它运行得很好,逻辑似乎没问题,但是如果我“自由地”运行它,那么分页符完全关闭。添加一些MsgBox指令,我可以看到当我读取HPageBreaks.Count(或垂直)时,我得到了错误的值。 (如果我手动执行代码应该做什么,我可以检查正确的。)

在许多论坛上搜索,我看到一些丑陋的变通办法,例如强制重置PaperSize(ws.PageSetup.PaperSize = ws.PageSetup.PaperSize)。在尝试了其中一些之后,似乎工作得更好的是在更改为PageSetup之前关闭PrintCommunication,然后将其重新打开。这在我的大多数纸张上运行良好,但在非常大的纸张上(~750行x 80列,几乎所有带公式的单元格),它根本就没有。

这是代码的摘录:

    'Reset page breaks
    .ResetAllPageBreaks

    'Set minimum acceptable zoom factor
    Application.PrintCommunication = False   'This is the ugly workaround
    .PageSetup.Zoom = 60
    Application.PrintCommunication = True

    MsgBox "Zoom = " & .PageSetup.Zoom    'Only for debugging

    'Calculate the number of pages in width
    Application.PrintCommunication = False
    NPagesWide = .VPageBreaks.Count + 1
    Application.PrintCommunication = True

    MsgBox "NPagesWide = " & NPagesWide

    'Find the higher zoom factor that can fit that number of pages
    Application.PrintCommunication = False
    .PageSetup.Zoom = 100
    Application.PrintCommunication = True
    Do While .VPageBreaks.Count > NPagesWide - 1
        Application.PrintCommunication = False
        .PageSetup.Zoom = .PageSetup.Zoom - 5
        Application.PrintCommunication = True
    Loop

    MsgBox "Zoom = " & .PageSetup.Zoom

    'Set average width per page and initialize column pointer
    If HasTitleColumns Then     'Defined earlier
        PageWidth = (PrintArea.Width + TitleColumns.Width * (NPagesWide - 1)) / NPagesWide
        j = TitleColumns.Columns(TitleColumns.Columns.Count).Column + 1
    Else
        PageWidth = PrintArea.Width / NPagesWide
        j = 1
    End If

    'Cycle vertical page breaks
    For i = 1 To NPagesWide - 1
        'Set width of TitleColumns
        If HasTitleColumns Then
            CumulWidth = TitleColumns.Width
        Else
            CumulWidth = 0
        End If
        'Cumulate columns width until the available page width
        Do While CumulWidth + .Columns(j).Width <= PageWidth
            CumulWidth = CumulWidth + .Columns(j).Width
            j = j + 1
        Loop
        'Add the break
        .VPageBreaks.Add .Columns(j + 1)
    Next i

为什么会发生这种情况的任何想法,我该如何解决?

谢谢,

2 个答案:

答案 0 :(得分:2)

VBA代码在调试模式下按F8时工作正常时,我建议对该问题提出一般性建议,但在点击F5运行整个宏后它不起作用。

提示1。尽可能使用ThisWorkbook.ActiveSheet代替ActiveWorkbook.ActiveSheet来引用正确的工作表。使用ThisWorkbook.Application代替Application.可能是您在后台运行了另一个Addin程序,将ActiveSheet切换为您可能不知道的其他内容。检查启用的其他宏并删除任何不使用的宏。因此,在代码中的任何重要内容之前,请尝试使用ThisWorkbook.Activate获取工作表的焦点。请参阅该页面上的图表:http://analystcave.com/vba-tip-day-activeworkbook-vs-thisworkbook/

提示2。强制Excel以不同的方式等待DoEvents

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'Place this line of code at the very top of module
Sleep 1   'This will pause execution of your program for 1 ms

https://stackoverflow.com/a/3891017/1903793 https://www.fmsinc.com/microsoftaccess/modules/examples/AvoidDoEvents.asp

或者:

Application.Calculate 
If Not Application.CalculationState = xlDone Then
    DoEvents
End If

https://stackoverflow.com/a/11277152/1903793

提示3。如果上述内容仍不能用于刷新使用:

ThisWorkbook.Connections("ConectionName").Refresh
ThisWorkbook.Application.CalculateUntilAsyncQueriesDone 

https://stackoverflow.com/a/26780134/1903793

答案 1 :(得分:0)

我的另一个解决方法是将PrintArea设置为new(不使用.PrintCommunication = false)

wks.PageSetup.PrintArea = wks.PageSetup.PrintArea

此解决方法不会影响任何pagesetup设置(与.Zoom属性不同)

仅当PageView设置为xlPageLayoutView且运行宏时“printarea”(UsedRange大于PrintArea)之外的数据才会出现此问题。

因此,在执行变通方法之前,您可以检查工作表是否在PageLayoutView中。如果工作表在任何其他视图中,则pagebreaks.count在此处始终正常工作。