There is a frequent need to get a list of ranges for printed pages - such as when making an index to items in a worksheet. This macro makes an array of references in page number order.
The following message shows a way of using the array to find specific items in the worksheet and get the page numbers. It uses page break positions.
There is a caveat that it is necessary to check the output. Best way is to check the page number of an item in an end page. Printing still does not seem to be an exact science. For example, its seems necessary to do a PrintPreview at the beginning of the macro to set the page breaks. You will see the note concerning a bug if the Active Cell is in the page range.
The following message shows a way of using the array to find specific items in the worksheet and get the page numbers. It uses page break positions.
There is a caveat that it is necessary to check the output. Best way is to check the page number of an item in an end page. Printing still does not seem to be an exact science. For example, its seems necessary to do a PrintPreview at the beginning of the macro to set the page breaks. You will see the note concerning a bug if the Active Cell is in the page range.
Code:
'=============================================================================
'- GET AN INDEX LIST OF PRINT PAGE RANGES
'- 3 dimension array : Page Top Left cell. Bottom Right cell. Page range.
'=============================================================================
'*****************************************************************************
'- *** PRINTING IS NOT AN EXACT SCIENCE ***
'- *** SEEMS NECESSARY TO PREVIEW THE DATA SHEET FIRST TO SET PAGE BREAKS ***
'- *** CHECK AN END PAGE ITEM IN THE FINAL OUTPUT WITH PRINTPREVIEW ***
'*****************************************************************************
'- **Overcomes Excel bug that gives an error message if the ActiveCell
'- is within the print range. Ref. [URL]http://support.microsoft.com/kb/210663[/URL]
'- Checks to see if there is an existing Print_Area set
'- Different methods for print order Down/Over or Over/Down
'- Brian Baulsom March 2010
'=============================================================================
Option Base 1
'=============================================================================
Public PagesArray() ' PUBLIC ARRAY CAN BE ACCESSED BY OTHER CODE MODULES
' ' Run from the other code module
'===========================================================================
Dim ws As Worksheet
Dim AllSheetsRange As Variant ' set to "Print_Area" reference if it exists
Dim PageNumber As Long
Dim LastCell As Range
Dim LastRow As Long
Dim LastCol As Integer
Dim PageCount As Integer
'- Horizontal PB
Dim HPBnumber As Integer
Dim HPBcount As Integer
Dim HPB As Object
'- Vertical PB
Dim VPBnumber As Integer
Dim VPBcount As Integer
Dim VPB As Object
'- Single page reference
Dim TopRow As Long
Dim TopCol As Integer
Dim BottomRow As Long
Dim BottomCol As Integer
'- array for pages
Dim PageSetupOrder As Long ' Down/Over or Over/Down
Dim NewSet As Boolean ' Set of pages depending on the print order
Dim rsp
'=============================================================================
'- MAIN ROUTINE
'=============================================================================
Sub PAGE_RANGES_TO_ARRAY()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
'- PRINT RANGE
Set ws = Worksheets("Data")
On Error Resume Next
'=======================================
Set AllSheetsRange = ws.Range("Print_Area") ' SEE IF PRINT RANGE EXISTS
'=======================================
If Err.Number <> 0 Then ' THE RANGE DOES NOT EXIST
'---------------------------------------------------------------------
'- GET LAST *REAL* USED ROW & COLUMN (used in case there are empty cells at the end)
'- ROW
Set LastCell = ws.Cells.Find(What:="*", After:=Range("IV65536"), _
LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
LastRow = LastCell.Row
'- COLUMN
Set LastCell = ws.Cells.Find(What:="*", After:=Range("IV65536"), _
LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious)
LastCol = LastCell.Column
'---------------------------------------------------------------------
Else
LastRow = AllSheetsRange.Rows.Count
LastCol = AllSheetsRange.Columns.Count
End If
'-------------------------------------------------------------------------
Err.Clear
On Error GoTo 0 ' reset to normal error trapping
'-------------------------------------------------------------------------
'- PAGES & PAGE BREAKS
With ws
.Activate ' activate sheet for Excel 4 Macro & cell Activate
.PrintPreview
PageCount = Application.ExecuteExcel4Macro("GET.DOCUMENT(50)")
'---------------------------------------------------------------------
'- ACTIVATE A CELL OUTSIDE THE PRINT AREA TO STOP EXCEL ERROR MESSAGE
.Range("A65536").Activate
'---------------------------------------------------------------------
PageSetupOrder = .PageSetup.Order ' Down/Over =1. Over/Down=2
HPBcount = .HPageBreaks.Count
VPBcount = .VPageBreaks.Count
End With
'-------------------------------------------------------------------------
ReDim PagesArray(PageCount, 3)
'*************************************************************************
' SHOW 'PROPERTIES' MSGBOX FOR TESTING (remove comments ')
' ShowPropertiesMsg
' If rsp = vbCancel Then GoTo GetOut
'*************************************************************************
'=========================================================================
'- DIFFERENT METHODS DEPENDING ON PRINT ORDER
'=========================================================================
If PageSetupOrder = 1 Or VPBcount = 0 Then
DOWN_OVER
Else
OVER_DOWN
End If
'-------------------------------------------------------------------------
'- GO TO TOP OF MAIN SHEET
Application.Goto reference:=ws.Range("A1"), Scroll:=True
'*************************************************************************
'- READ THE ARRAY TO WORKSHEET FOR CHECKING (remove comment ')
' READ_ARRAY ' SUBROUTINE reads the array to a worksheet
'*************************************************************************
Application.ScreenUpdating = True
'MsgBox ("Array done")
GetOut:
Application.StatusBar = False
End Sub
'=========== END OF MAIN ROUTINE =============================================
'=============================================================================
'- SUBROUTINE : PRINT ORDER OVER/DOWN
'=============================================================================
Private Sub OVER_DOWN()
PageNumber = 1
While PageNumber <= PageCount
Application.StatusBar = PageNumber & "/" & PageCount
'---------------------------------------------------------------------
'- PAGE 1
If PageNumber = 1 Then
NewSet = False
'-----------------------------------------------------------------
'- row
HPBnumber = 0
TopRow = AllSheetsRange.Cells(1, 1).Row
BottomRow = ws.HPageBreaks(1).Location.Row - 1
'-----------------------------------------------------------------
'- column
TopCol = AllSheetsRange.Cells(1, 1).Column
VPBnumber = 1
BottomCol = ws.VPageBreaks(1).Location.Column - 1
'---------------------------------------------------------------------
'- NEW SET (VERTICAL PAGEBREAK = 1)
ElseIf NewSet = True Then
TopCol = AllSheetsRange.Cells(1, 1).Column
BottomCol = ws.VPageBreaks(1).Location.Column - 1
NewSet = False
'---------------------------------------------------------------------
'- LAST VERTICAL PAGEBREAK -> NEXT HORIZONTAL PAGEBREAK (New Set)
ElseIf VPBnumber = VPBcount Then
TopCol = ws.VPageBreaks(VPBnumber).Location.Column
BottomCol = LastCol
VPBnumber = 1
NewSet = True ' ************* CHANGE BELOW
'---------------------------------------------------------------------
'- INTERMEDIATE PAGE - Next Vertical Page Break
Else
TopCol = ws.VPageBreaks(VPBnumber).Location.Column
BottomCol = ws.VPageBreaks(VPBnumber + 1).Location.Column - 1
VPBnumber = VPBnumber + 1
End If
'---------------------------------------------------------------------
'- PAGE REFERENCES TO THE ARRAY
PagesArray(PageNumber, 1) = Cells(TopRow, TopCol).Address
PagesArray(PageNumber, 2) = Cells(BottomRow, BottomCol).Address
PagesArray(PageNumber, 3) = PagesArray(PageNumber, 1) & ":" & PagesArray(PageNumber, 2)
PageNumber = PageNumber + 1
'=====================================================================
'- END OF PRINT SET (NewSet = True at last VERTICAL Page break above)
'- New HORIZONTAL ROW & back to the LEFT
'=====================================================================
If PageNumber < PageCount And NewSet Then
HPBnumber = HPBnumber + 1
TopRow = BottomRow + 1
If HPBnumber < HPBcount Then
BottomRow = ws.HPageBreaks(HPBnumber + 1).Location.Row - 1
Else
BottomRow = LastRow
End If
End If
'---------------------------------------------------------------------
Wend
End Sub
'=============================================================================
'- SUBROUTINE : PRINT ORDER DOWN/OVER
'=============================================================================
Private Sub DOWN_OVER()
PageNumber = 1
While PageNumber <= PageCount
Application.StatusBar = PageNumber & "/" & PageCount
'---------------------------------------------------------------------
'- PAGE 1
If PageNumber = 1 Then
NewSet = False
HPBnumber = 1
VPBnumber = 0
TopRow = AllSheetsRange.Cells(1, 1).Row
BottomRow = ws.HPageBreaks(1).Location.Row - 1
TopCol = AllSheetsRange.Cells(1, 1).Column
If VPBcount = 0 Then
BottomCol = LastCol
Else
BottomCol = ws.VPageBreaks(1).Location.Column - 1
End If
'---------------------------------------------------------------------
'- NEW SET OF VERTICAL PAGES
ElseIf NewSet = True Then
HPBnumber = 1
TopRow = AllSheetsRange.Cells(1, 1).Row
BottomRow = ws.HPageBreaks(1).Location.Row - 1
NewSet = False
'---------------------------------------------------------------------
'- LAST HORIZONTAL PAGEBREAK -> NEXT VERTICAL PAGEBREAK (New Set)
ElseIf HPBnumber = HPBcount Then
TopRow = ws.HPageBreaks(HPBnumber).Location.Row
BottomRow = LastRow
NewSet = True
'---------------------------------------------------------------------
'- INTERMEDIATE PAGE
Else
TopRow = ws.HPageBreaks(HPBnumber).Location.Row
BottomRow = ws.HPageBreaks(HPBnumber + 1).Location.Row - 1
HPBnumber = HPBnumber + 1
End If
'---------------------------------------------------------------------
'- PAGE REFERENCES TO THE ARRAY
PagesArray(PageNumber, 1) = Cells(TopRow, TopCol).Address
PagesArray(PageNumber, 2) = Cells(BottomRow, BottomCol).Address
PagesArray(PageNumber, 3) = PagesArray(PageNumber, 1) & ":" & PagesArray(PageNumber, 2)
PageNumber = PageNumber + 1
'=====================================================================
'- END OF PRINT SET (NewSet = True at last horizontal Page break above)
'- NEW VERTICAL PAGE BREAK
'=====================================================================
If PageNumber < PageCount And NewSet Then
VPBnumber = VPBnumber + 1
If VPBnumber < VPBcount Then
TopCol = BottomCol + 1
BottomCol = ws.VPageBreaks(VPBnumber + 1).Location.Column - 1
Else
TopCol = ws.VPageBreaks(VPBcount).Location.Column
BottomCol = LastCol
End If
End If
'---------------------------------------------------------------------
Wend
End Sub
'========== EOP ==============================================================
'=============================================================================
'- SUBROUTINE : READ THE ARRAY TO WORKSHEET "ReadArray"
'- makes a new sheet if it does not exist
'=============================================================================
Private Sub READ_ARRAY()
With Worksheets("ReadArray")
.Range("A:D").ClearContents
.Range("A1:D1").Value = Array("Page", "Top Left", "Bottom Right", "Range")
Application.ScreenUpdating = False
'---------------------------------------------------------------------
'- ARRAY DATA TO WORKSHEET
For PageNumber = 1 To UBound(PagesArray) ' pagecount
.Cells(PageNumber + 1, 1).Value = PageNumber
.Cells(PageNumber + 1, 2).Value = PagesArray(PageNumber, 1)
.Cells(PageNumber + 1, 3).Value = PagesArray(PageNumber, 2)
.Cells(PageNumber + 1, 4).Value = PagesArray(PageNumber, 3)
Next
'---------------------------------------------------------------------
.Activate
End With
End Sub
'========= EOP ===============================================================
'=============================================================================
'- SUBROUTINE : MESSAGE BOX SHEET PROPERTIES
'=============================================================================
Private Sub ShowPropertiesMsg()
Dim MyMsg As String
MyMsg = "Total Pages : " & PageCount & vbCr _
& "Horizontal PB : " & HPBcount & vbCr _
& "Vertical PB : " & VPBcount & vbCr _
& "Last Row : " & LastRow & vbCr _
& "Last Column : " & LastCol & vbCr _
& "Print Order : " & IIf(PageSetupOrder = 1, "Down/Over", "Over/Down")
rsp = MsgBox(MyMsg, vbOKCancel, "Sheet : '" & ws.Name & "'")
End Sub
'==============================================================================