Sub List_Number_Of_Breaks_in_Months_in_Print_Range_Of_Active_Sheet()
Dim currentPageBreakRowNumber As Long
Dim totalNumberOfBreaksForCurrentYear As Integer
Dim monthBeforeBreak As Long
Dim monthAfterBreak As Long
Dim currentYear As Integer
Dim previousYear As Integer
Dim printRange As String
Dim firstYearInPrintRange As Integer
Dim lastYearInPrintRange As Integer
Dim numberOfYears As Integer
Dim currentMonth As Long
Dim messge As String
Dim columnLetterDatesAreIn As String
Dim previousView As Integer
previousView = ActiveWindow.View
ActiveWindow.View = xlPageBreakPreview
ActiveWindow.Zoom = 70
On Error GoTo Exit_Sub
'If we don't select the last cell in the used range, then we won't get all of the page breaks in the print range!
Range("A" & ActiveSheet.UsedRange.Rows.Count).Select
With ActiveSheet
printRange = ""
'Prompt the user to select the print range, but give them the option to skip by pressing the [Esc] key or Xing out of dialogue box.
'Line #1
printRange = RangeSelectionPrompt("Select Print Range (Press [Esc] to keep previous.)"):
'Get the print range from Excel if the user chose not to input it in.
If printRange <> "" Then
.PageSetup.PrintArea = printRange
Else
printRange = .PageSetup.PrintArea
End If
Try_Again:
'If the number of columns in the print range is more than one,
If Range(printRange).Columns.Count > 1 Then
'Ask specifically which column contains the dates.
columnLetterDatesAreIn = InputBox("Please type in the column letter where the dates are." & vbCrLf & vbCrLf & "(Not case-sentive.)", "Type in [1] to quit this program", "")
'Make sure that a letter or letters is inputted, otherwise prompt the user to try again.
If Consists_Of_Only_English_Alphabet_Letters(columnLetterDatesAreIn) = False Then
'But if a letter wasn't entered but it was a 1, then QUIT.
If columnLetterDatesAreIn = "1" Then
GoTo Exit_Sub
Else 'Otherwise, go through with trying again.
GoTo Try_Again
End If
End If
'Make the column letter(s) all uppercase if they are not.
columnLetterDatesAreIn = UCase(columnLetterDatesAreIn)
Else
'Get the column number from the single column that is in the print range.
columnLetterDatesAreIn = Split(.Range(printRange)(1).Address, "$")(1)
MsgBox "Print Range: " & printRange
End If
'Check to see that the first and last cells in the 'column with the dates' in the print range are dates.
If IsDate(.Range(printRange)(1).Value) = False Then
MsgBox "The first cell in the print range is not a date" & vbCrLf & vbCrLf & "Print range: " & printRange
GoTo Exit_Sub
End If
If IsDate(.Range(printRange)(.Range(printRange).Rows.Count, 1)) = False Then
MsgBox "The last cell in the print range is not a date" & vbCrLf & vbCrLf & "Print range: " & printRange
GoTo Exit_Sub
End If
'A line of code which allows the user to break the program's execution should it take too long (for an ENTIRE column as the print range, for example)
DoEvents
'Now do the calculations:
firstYearInPrintRange = Year(.Range(printRange)(1).Value)
lastYearInPrintRange = Year(.Range(printRange)(.Range(printRange).Rows.Count, 1))
numberOfYears = lastYearInPrintRange - firstYearInPrintRange + 1
ReDim years_Months_Breaks(1 To numberOfYears, 1 To 12, 1 To 2) As Integer 'Fill an array with 12 arguments whose value is 0.
totalNumberOfBreaksForCurrentYear = 1
previousYear = firstYearInPrintRange
For i = 1 To .HPageBreaks.Count
currentPageBreakRowNumber = .HPageBreaks(i).Location.Row 'The location of each break.
monthBeforeBreak = Month(.Range(columnLetterDatesAreIn & currentPageBreakRowNumber - 1).Value)
monthAfterBreak = Month(.Range(columnLetterDatesAreIn & currentPageBreakRowNumber).Value)
'If the break is within a month (the page break row is the same month as the row above it),
If (monthBeforeBreak = monthAfterBreak) Then
currentYear = Year(.Range(columnLetterDatesAreIn & currentPageBreakRowNumber).Value)
'Line #2
'Range(columnLetterDatesAreIn & currentPageBreakRowNumber).Select: MsgBox Range(columnLetterDatesAreIn & currentPageBreakRowNumber).Value & " " & monthAfterBreak
'If we have advanced to a new year, add the total number of page breaks to the array (just put with the first month for simplicity).
If currentYear > previousYear Then
years_Months_Breaks(previousYear - firstYearInPrintRange + 1, 1, 1) = totalNumberOfBreaksForCurrentYear - 1
totalNumberOfBreaksForCurrentYear = 1
End If
previousYear = currentYear
totalNumberOfBreaksForCurrentYear = totalNumberOfBreaksForCurrentYear + 1
years_Months_Breaks(currentYear - firstYearInPrintRange + 1, monthBeforeBreak, 2) = years_Months_Breaks(currentYear - firstYearInPrintRange + 1, monthBeforeBreak, 2) + 1
End If
Next
'If we have advanced to a new year, add the total number of page breaks to the array (just put with the first month for simplicity).
years_Months_Breaks(previousYear - firstYearInPrintRange + 1, 1, 1) = totalNumberOfBreaksForCurrentYear - 1
'Display the total number of breaks for all months in all years.
'MsgBox "Total number of PBs: " & .HPageBreaks.Count
'Display the frequency of breaks in months. Do it for every year.
currentYear = 1
Do While currentYear <= numberOfYears
currentMonth = 1
messge = "Number of PBs in year: " & firstYearInPrintRange + currentYear - 1 & ": " & years_Months_Breaks(currentYear, 1, 1) & vbCrLf & vbCrLf
Do While currentMonth <= 12
messge = messge & Month_Name(currentMonth) & ": " & years_Months_Breaks(currentYear, currentMonth, 2) & vbCrLf
currentMonth = currentMonth + 1
Loop
MsgBox messge
currentYear = currentYear + 1
Loop
End With
'Perhaps select this cell to bring you back to the top.
Range(columnLetterDatesAreIn & "1").Select
ActiveWindow.View = previousView
Exit Sub
Exit_Sub:
ActiveWindow.View = previousView
End Sub
Sub Test__Month_Name()
MsgBox Month_Name(1)
End Sub
Function Month_Name(monthNumber As Long)
Select Case monthNumber
Case 1
Month_Name = "January "
Case 2
Month_Name = "February "
Case 3
Month_Name = "March "
Case 4
Month_Name = "April "
Case 5
Month_Name = "May "
Case 6
Month_Name = "June "
Case 7
Month_Name = "July "
Case 8
Month_Name = "August "
Case 9
Month_Name = "September"
Case 10
Month_Name = "October "
Case 11
Month_Name = "November "
Case 12
Month_Name = "December "
End Select
End Function
Sub Test__RangeSelectionPrompt()
MsgBox RangeSelectionPrompt("Choose Cells")
End Sub
Function RangeSelectionPrompt(titleOfRangeSelectionPromptBox As String)
'Code is from http://www.vbaexpress.com/forum/showthread.php?763-Solved-Inputbox-Cell-Range-selection-Nothing-selected-or-Cancel&p=6680&viewfull=1#post6680
Dim Selectedarea As Range
On Error Resume Next
Set Selectedarea = Application.InputBox(prompt:="Left click on the top-left cell and drag to the botSomething-right cell.", _
title:=titleOfRangeSelectionPromptBox, Default:=Selection.Address, Type:=8)
'If the user clicked on cancel,
If Selectedarea Is Nothing Then
Selectedarea = ""
Exit Function
End If
RangeSelectionPrompt = Selectedarea.Address
End Function
Sub Test__Consists_Of_Only_English_Alphabet_Letters()
MsgBox Consists_Of_Only_English_Alphabet_Letters("A1")
MsgBox Consists_Of_Only_English_Alphabet_Letters("A")
MsgBox Consists_Of_Only_English_Alphabet_Letters("a")
MsgBox Consists_Of_Only_English_Alphabet_Letters("AB")
End Sub
'A regular expression to check whether the current character of focus is a lower or uppercase letter of the English alphabet.
'Source: https://stackoverflow.com/questions/29633517/how-can-i-check-if-a-string-only-contains-letters
'Counterpart to the built-in "IsNumeric()" function.
Function Consists_Of_Only_English_Alphabet_Letters(strValue As String) As Boolean
Consists_Of_Only_English_Alphabet_Letters = strValue Like WorksheetFunction.Rept("[a-zA-Z]", Len(strValue))
End Function