Home » excel » vba – Hide/Unhide Excel Sheets based on multiple cell values

vba – Hide/Unhide Excel Sheets based on multiple cell values

Posted by: admin May 14, 2020 Leave a comment

Questions:

I have an Excel workbook which contains multiple sheets. I want to hide/unhide sheets based on cell values in Main sheet cells B3:B8. Values in Main sheet are changed by the user from pre-defined list.

Eg. If “A” exists in the “Config” column, then unhide sheet “A” in my workbook.

Workbook

At the moment I have following code, which works, but looks
clunky, Excel flickers as the code runs every time a value is changed in “Config” column:

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim i As Integer
    Sheets("A").Visible = False
    Sheets("B").Visible = False
    Sheets("C").Visible = False
    Sheets("D").Visible = False

    For i = 3 To 8
        If InStr(1, Cells(i, 2), "A") Then
        Sheets("A").Visible = True
        ElseIf InStr(1, Cells(i, 2), "B") Then
        Sheets("B").Visible = True
        ElseIf InStr(1, Cells(i, 2), "C") Then
        Sheets("C").Visible = True
        ElseIf InStr(1, Cells(i, 2), "D") Then
        Sheets("D").Visible = True
        End If
    Next i

End Sub

I also tried to run this macro from a button, but it stops with first TRUE value (a sheet becomes unhidden).

How to&Answers:

I would use this method:

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim i As Integer
    Sheets("A").Visible = xlSheetHidden
    Sheets("B").Visible = xlSheetHidden
    Sheets("C").Visible = xlSheetHidden
    Sheets("D").Visible = xlSheetHidden

    Application.ScreenUpdating = False

    For i = 3 To 8
        If InStr(1, Cells(i, 2), "A") Then Sheets("A").Visible = xlSheetVisible
        If InStr(1, Cells(i, 2), "B") Then Sheets("B").Visible = xlSheetVisible
        If InStr(1, Cells(i, 2), "C") Then Sheets("C").Visible = xlSheetVisible
        If InStr(1, Cells(i, 2), "D") Then Sheets("D").Visible = xlSheetVisible
    Next i

    Application.ScreenUpdating = True
End Sub

Answer:

Another way to do this would be:

Private Sub Worksheet_Change(ByVal Target As Range)

Dim RNG As Range, CL As Range
Dim WS As Worksheet

Application.ScreenUpdating = False

Set RNG = Sheets("Main").Range("B3:B8")
If Not Intersect(Target, RNG) Is Nothing Then
    Application.ScreenUpdating = False
    For Each WS In ThisWorkbook.Worksheets
        If WS.Name <> "Main" Then
            With RNG
            Set CL = .Find(What:=WS.Name, LookIn:=xlValues, LookAt:=xlWhole)
                If Not CL Is Nothing Then
                    WS.Visible = xlSheetVisible
                Else
                    WS.Visible = xlSheetHidden
                End If
            End With
        End If
    Next WS
End If

Application.ScreenUpdating = True

End Sub

More versatile and more dynamic

EDIT: To also check if Target intersects with your lookup range to prevent triggering macro unwanted.

Answer:

To help optimize the running and have it look better use Application.ScreenUpdating. It will reduce the flickering by not trying to repaint the scrren until the Sub has finished running. If the rest of the program runs with no issue it should be all you need

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim i As Integer
    Sheets("A").Visible = False
    Sheets("B").Visible = False
    Sheets("C").Visible = False
    Sheets("D").Visible = False

    For i = 3 To 8
        If InStr(1, Cells(i, 2), "A") Then
        Application.ScreenUpdating = False
        Sheets("A").Visible = True
        ElseIf InStr(1, Cells(i, 2), "B") Then
        Application.ScreenUpdating = False
        Sheets("B").Visible = True
        ElseIf InStr(1, Cells(i, 2), "C") Then
        Application.ScreenUpdating = False
        Sheets("C").Visible = True
        Application.ScreenUpdating = False
        ElseIf InStr(1, Cells(i, 2), "D") Then
        Sheets("D").Visible = True
        End If
    Next i
Application.sScreenUpdating = True
End Sub

I also agree with ‘s comment. Ifs would be better. ElseIf assumes only one condition is the correct one when there could be multiple iterations.

edit:
Also a though: It looks like the way its set up you intend that any value between B3:B8 that has an “A” will show page “A”. If you dedicate it differently B3 = “A” , B4=”B” etc and so on, you can change the conditionals to If Target.Address = "$B$3" Then and have B# be the on/off to sheet”A” with any non-empty value.

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.ScreenUpdating = False
  If Target.Address = "$B$3" Then
    If IsEmpty(Sheet1.Range("B3")) = False Then
       Sheets("A").Visible = True
    Else 
       Sheets("A").Visible = False
    End If
  End If


        ''etc etc and so on

 Application.ScreenUpdating = True
End Sub