Prepare for the show: A framework for hiding rows and columns in your spreadsheet applications

Prepare for the Show
Most sheets I create look something like this.

Hiding a bunch of rows and columns in a sheet before showing it to your boss is inevitable.  I insert blank rows and columns around a table, so I can use the CurrentRegion property of the Range Object in my code. I add labels to all my named ranges in the sheet. I split out complex formulas into a couple of columns. Ultimately I end up with a lot of rows and columns to hide.  I desperately needed a framework to hide and un-hide rows and columns in all my sheets. I experimented with a lot of methods before settling down with one and I would definitely like to know if you have a better way to do it.

I consider the following, essential in a framework for hiding rows and columns:

  1. Inserting rows and columns in later should not leave you adjusting your code all over again. Here is where the recording and playing method fails miserably. Having a couple of arrays with row and column numbers is also not immune to inserting new rows and columns.
  2. In addition to hiding cells, you should also allow for un-hiding essential rows and columns that were inadvertently hidden.
  3. Another consideration is that, you might have to conditionally hide or show some cells in your dashboards
  4. Finally, it should also be able to hide unused columns to the right, and rows below the used cells

These considerations point to a system that uses markers right on the sheet and not explicitly specified in code. So I decided to go with Boolean markers on the first row and column of every sheet.  The entire row or column is hidden only if the value is set to True, otherwise, it is un-hidden.

Prepare for the Show
Most sheets I create look something like this.

Download HideRowsColumns.xlsm from Dropbox to give it a spin. I have also added in a couple of cover macros you can use in your projects with minor tweaks. You definitely have to un-hide all the cells in a sheet, to prepare your sheets for development. I have added in a sub for that as well. You may also explicitly specify the ranges you have stored the Boolean markers in – Check the ‘HideConditional’ Sub in ‘modCovers’. You can even loop through a bunch of sheets to prepare your entire workbook for the show!

Prepared for the Show!
The code then prepares the sheet for the Show!

Read on, if you are interested in understanding how the code works:

'###################################################################
'PrepareSheet: Macro to Hide or Un-Hide Rows and Columns in a sheet
'and to prepare it for viewing.
'###################################################################
'Arguments:
'WhichSheet - Which Worksheet Object to work on
'HideRowsRange - The Range that has Boolean Markers to hide
'rows
'HideColumnRange - The Range that has Boolean Markers to hide
'Columns
'HideUnusedCells - Boolean variable to specify if the user would
'like to unhide all the unused cells to the right and bottom
'HideGridLines - Boolean variable to specify if the user would
'like to Show/Hide Gridlines
'HideHeadings - Boolean variable to specify if the user would
'like to Show/Hide Row and Column Headings
'HideFormulaBar - Boolean variable to specify if the user would
'like to Show/Hide the FormulaBar
'###################################################################
'Author     : Ejaz Ahmed
'Date       : 25 April 2014
'Email      : StrugglingToExcel@outlook.com
'Website    : http://strugglingtoexcel.wordpress.com/
'###################################################################
Sub PrepareSheet(Optional ByRef WhichSheet As Worksheet, _
    Optional ByRef HideRowsRange As Range, _
    Optional ByRef HideColumnsRange As Range, _
    Optional ByVal HideUnusedCells As Boolean = True, _
    Optional ByVal HideGridLines As Boolean = True, _
    Optional ByVal HideHeadings As Boolean = True, _
    Optional ByVal HideFormulaBar As Boolean = False)

Dim rngEach As Range
Dim rngTemp As Range

'Work on the Active sheet if not specified
If WhichSheet Is Nothing Then
    Set WhichSheet = Application.ActiveSheet
End If
WhichSheet.Activate

'Use the first Column of the UsedRange, if not specified
If HideRowsRange Is Nothing Then
    Set HideRowsRange = WhichSheet. _
    UsedRange.Columns(1)
End If

'Use the first Row of the UsedRange, if not specified
If HideColumnsRange Is Nothing Then
    Set HideColumnsRange = WhichSheet. _
        UsedRange.Rows(1)
End If

'Hide the Unused cells if the user chose to
If HideUnusedCells Then
    'Unhide everyhting first (to get the right UsedRange)
    WhichSheet.Cells.EntireColumn.Hidden = False
    WhichSheet.Cells.EntireRow.Hidden = False
    'Get the Used Range
    Set rngTemp = WhichSheet.UsedRange
    'Get the last Row in the UsedRange
    Set rngTemp = rngTemp.Rows(rngTemp.Rows.Count)
    'Get the Next Row in the Sheet
    Set rngTemp = WhichSheet.Rows(rngTemp.Row + 1)
    'Get all the rows below it
    Set rngTemp = Range(rngTemp, rngTemp.End(xlDown))
    'Hide those Rows
    rngTemp.EntireRow.Hidden = True
    'Do the same for the Columns
    Set rngTemp = WhichSheet.UsedRange
    Set rngTemp = rngTemp.Columns(rngTemp.Columns.Count)
    Set rngTemp = WhichSheet.Columns(rngTemp.Column + 1)
    Set rngTemp = Range(rngTemp, rngTemp.End(xlToRight))
    rngTemp.EntireColumn.Hidden = True
End If

'I could have achieved the same effect with the following
'commented out code, but the code written above is just
'way faster.
'WhichSheet.Cells.EntireColumn.Hidden = True
'WhichSheet.Cells.EntireRow.Hidden = True
'WhichSheet.UsedRange.EntireColumn.Hidden = False
'WhichSheet.UsedRange.EntireRow.Hidden = False

'Loop through HideRowsRange
For Each rngEach In HideRowsRange.Cells
    If rngEach.Value = True Then
        'Hide the Row if the cell's value is set to True
        rngEach.EntireRow.Hidden = True
    Else
        'Unhide the row otherwise
        rngEach.EntireRow.Hidden = False
    End If
Next rngEach

'Do the same thing for the Columns
For Each rngEach In HideColumnsRange.Cells
    If rngEach.Value = True Then
        rngEach.EntireColumn.Hidden = True
    Else
        rngEach.EntireColumn.Hidden = False
    End If
Next rngEach

'Hide/Show Gridlines, Headings and FormulaBar
ActiveWindow.DisplayGridlines = Not HideGridLines
ActiveWindow.DisplayHeadings = Not HideHeadings
Application.DisplayFormulaBar = Not HideFormulaBar
'Scrollback up after all the hiding
ActiveWindow.ScrollColumn = 1
ActiveWindow.ScrollRow = 1
End Sub

8 Comments

  1. Nice code. I think that I will use it even for sheets without dummy rows / columns as the hide non used, grid lines and headings is exactly what I would like to present in “boss mode”. I think it can even used the macro in the activate sheet event to prevent any user to enter on edit mode by mistake.

    • I totally agree, you can use this even if you don’t have to hide Rows/Columns. That is why I coded it such that only a “True” value will hide Rows/Columns.

      Glad you like it.

    • However, there is the issue with Excel where it does not update used ranges unless you reopen the file. So it is safe to put down a couple of True’s to the right and bottom of your used range.

  2. Luke Cole

    Hi there. I like the idea. However, I am always trying to avoid ways of looping through cells/ranges it can really kill the performance of a sheet. With the TRUE/FALSE distinction there is no clever way to select a range quickly.

    Another idea is to generate errors on the rows/columns you want to hide e.g. =IF(B2<>””, NA(), TRUE) . Then for example use

    Range(“A:A”).SpecialCells(xlCellTypeFormulas, 16).entirerow.hidden = True

    This avoids looping through cells/ranges and is a lot quicker for conditional hiding/showing.

    Find this specialCells extremely useful for avoiding looping through ranges/cells in certain circumstances.

    • Ejaz

      Hi Luke,

      Thank you for the suggestion and following my blog. I am afraid I have to disagree with you on part of your comment.

      Using a for each loop is very inefficient I agree. Because, it has to initialize a range object each at each iteration.

      Having a single range object, and looping through it using row and column numbers is not inefficient at all.

      In fact, even the special cells method has to perform a loop implicitly.

      Let me know what you think.

      Regards,
      Ejaz

      • Luke Cole

        Thanks Ejaz,

        I love your blog, full of really great ideas and expert code. I just thought this was one area I could contribute and add a little improvement. Sorry just love my vba as well, as it is only language can use at work (computers are severely locked down, so can’t really distribute an exe or a dll).

        The loop at:
        For Each rngEach In HideRowsRange.Cells

        is a performance killer!

        Agree that specialCells has some kind of internal implicit loop, however this is done natively on excel side, with only one call from vba to the worksheet. Every time the loop calls a range, it is crossing from vba to the excel worksheet side, and this is what hurts performance.

        You just cannot compete with specialCells performance from vba code (although range = variant, then loop through variant might come close).

        You can also use this with other enumerations of specialCells e.g.
        range.specialCells(xlCellTypeVisible).entirerow.hidden = false
        or
        range.specialCells(xlCellTypeBlanks).entirerow.hidden = true

        Did a quick test over 1000 iterations for 1000 rows with every second row marked to be hidden (with TRUE or NA())
        – loop over range = 147.05 seconds for 1000 iterations
        – specialCells method = 1.14 seconds for 1000 iterations

        Thanks – once again, your blog is brilliant, but just wanted to contribute and thought this was an area the code could be more efficient.

        Thanks Ejaz,

        Luke

        • Ejaz

          I have an optimized version, that I have been using for a while now. Did not realize I did not update my blog. Thank you for the suggestion. I will update my code.

          I’d be grateful, if you would give me some feedback on my other post as well.

  3. Craig

    Very helpful from both of you. Just what I needed. Cheers

Comments are closed