VBA: hide and unhide code not working - excel

I'm new to VBA and have been trying to write a code that hides and unhides rows based on the input value of a certain cell address. However, it doesn't work and I don't why. I have posted my code below:
Sub Hide()
If Worksheets("IS").Range("B8").Value = "Show All" Then
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
End If
If Worksheets("IS").Range("B8").Value = "Just Revenue" Then
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("28:165").EntireRow.Hidden = True
End If
If Worksheets("IS").Range("B8").Value = "Just Expenses" Then
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:27").EntireRow.Hidden = True
Worksheets("IS").Rows("160:165").EntireRow.Hidden = True
End If
If Worksheets("IS").Range("B8").Value = "Just Cogs" Then
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:27").EntireRow.Hidden = True
Worksheets("IS").Rows("64:165").EntireRow.Hidden = True
End If
If Worksheets("IS").Range("B8").Value = "Just Totals" Then
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:25").EntireRow.Hidden = True
Worksheets("IS").Rows("28:61").EntireRow.Hidden = True
Worksheets("IS").Rows("64:91").EntireRow.Hidden = True
Worksheets("IS").Rows("93:155").EntireRow.Hidden = True
End If
End Sub
Any help with why my code doesn't work or any tips to improve it would be much appreciative.

Rewriting for Worksheet_Change:
In your VBE, paste this code into the code sheet for the "IS" worksheet (double click it in the Project - VBAProject pane. If the Project - VBAProject pane is not visible in your VBE, go to View>>Project Explorer):
Private Sub Worksheet_Change(ByVal Target As Range)
'Ensure that we don't trigger another change event while this code is running
Application.EnableEvents = False
'Check if cell B8 triggered this change:
If Not Intersect(Target, Range("B8")) Is Nothing Then
'B8 changed... which means B8 is "Target" variable
Select Case Target.Value
Case "Show All"
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Case "Just Revenue"
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("28:165").EntireRow.Hidden = True
Case "Just Expenses"
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:27").EntireRow.Hidden = True
Worksheets("IS").Rows("160:165").EntireRow.Hidden = True
Case "Just Cogs"
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:27").EntireRow.Hidden = True
Worksheets("IS").Rows("64:165").EntireRow.Hidden = True
Case "Just Totals"
Worksheets("IS").Rows("12:165").EntireRow.Hidden = False
Worksheets("IS").Rows("12:25").EntireRow.Hidden = True
Worksheets("IS").Rows("28:61").EntireRow.Hidden = True
Worksheets("IS").Rows("64:91").EntireRow.Hidden = True
Worksheets("IS").Rows("93:155").EntireRow.Hidden = True
End Select
End If
'Turn events back on so this code triggers again
Application.EnableEvents = True
End Sub
There are quite a few events that we can hook VBA to (SelectionChange, DoubleClick, Workbook_Close, etc). In this case we are hooking to Worksheet_Change().
This code gets triggered every time this worksheet experiences a change. The Target variable will hold the range that triggered the event. So we test to see if that Target intersects with Range("B8") which means B8 was changed. Then we perform the code inside the If block.
I switched your If/ElseIf over to a Select/Case just because it makes for cleaner code since we are testing a single condition (the value of B8) over and over again.
In this code we also toggle off the Excel Applications EnableEvents feature. This feature is what allowed this Worksheet_Change() to get triggered in the first place. Often times in the code we make more changes to the worksheet (hiding rows or columns, for instance) which will trigger the application to run Worksheet_Change() again... while it's running Worksheet_Change() already. This can cause code to run superfluously and, often, cause an endless loop that makes excel crash.

This code needs to be pasted on the sheet where you want are wanting to execute the code. You will not need to qualify your ranges with the sheets once the code is there as well.
You can just refer directly to your range without the Worksheets("IS"). as so:
Rows("so and so").EntireRow.Hidden = True
You can also just refer to your TargetRange by variable now like so:
If MyTarget = "Just Revenue" Then
I inserted one of your conditions in the code as an example
Option Explicit
Private Sub worksheet_change(ByVal target As Range)
Dim MyTarget As Range
Set MyTarget = Range("B8")
If Not Intersect(target, MyTarget) Is Nothing Then
Application.EnableEvents = False
'Your CODE HERE
If MyTarget = "Show All" Then
Rows("12:165").EntireRow.Hidden = False
End If
Application.EnableEvents = True
End If
End Sub

Related

Rerun a macro when a combobox value in a userform is changed

I have a userform with a combobox to select the training type for various employee classes.
When the user selects one of the options from the dropdown menu it runs the macro below.
Private Sub TrainingType_Selection_Change()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Dim TrainingType_Selection As String
TrainingType_Selection = Hiring_Validation_Form.TrainingType_Selection.Value
If TrainingType_Selection = "Sustain - 30" Or TrainingType_Selection = "Sustain - 60" Then
Hiring_Validation_Form.LinkingECPID_Selection.Visible = True
Hiring_Validation_Form.LinkingECP_Label.Visible = True
End If
If TrainingType_Selection <> "New Hire" Then
Hiring_Validation_Form.ReqReasonLv1_Selection.Visible = False
Hiring_Validation_Form.Label6.Visible = False
Hiring_Validation_Form.ReqReasonLv2_Selection.Visible = False
Hiring_Validation_Form.Label11.Visible = False
End If
End Sub
The problem I'm running into is that if someone makes a selection from the drop-down menu and then changes their mind and selects another value from the drop-down menu it isn't re-running the macro. For example they change it from the above "New Hire" to "Sustain - 30". I have a clear button on the userform, but that clears the entire form which would not be ideal in a situation where the user only wants to change one input, not completely start over.
How do I get the TrainingType_Selection_Change() macro to re-run again when the combobox selection is changed
This line:
Application.ScreenUpdating = False
disables screen updates even after the macro has finished running.
Add
Application.ScreenUpdating = True
as the last line before End Sub to re-enable them.
I was able to figure out a way to address this issue by using AfterUpdate()
I added the below macro and it now updates the entire form when selections are changed.
Private Sub TrainingType_Selection_AfterUpdate()
TrainingType_Selection = Hiring_Validation_Form.TrainingType_Selection.Value
Hiring_Validation_Form.LinkingECPID_Selection.Visible = False
Hiring_Validation_Form.LinkingECP_Label.Visible = False
Hiring_Validation_Form.ReqReasonLv1_Selection.Visible = True
Hiring_Validation_Form.Label6.Visible = True
Hiring_Validation_Form.ReqReasonLv2_Selection.Visible = True
Hiring_Validation_Form.Label11.Visible = True
Hiring_Validation_Form.Label21.Visible = True
Hiring_Validation_Form.NewHireSup_Selection.Visible = True
Call TrainingType_Selection_Change
End Sub

Multiple Non-contiguous rows in excel Based on cell value

My goal is to be able to have a drop down list that hides certain non-contiguous rows in excel based off the name of the individual in the list I create. I have this code which I found off Youtube and was wondering what was wrong with it as it was not working. I am relatively new to VBA
Private Sub Worksheet_Calculate()
Dim Andrew, Robert, Michael As Range
Set Andrew = Range("K30")
Set Robert = Range("K30")
Set Michael= Range ("K30")
Select Case Andrew
Case Is = "Andrew": Rows("8:10").EntireRow.Hidden = True
Rows("11:12").EntireRow.Hidden = False
Rows("13:13").EntireRow.Hidden = True
Rows("14:25").EntireRow.Hidden = False
End Select
Select Case Robert
Case Is = "Robert"
Rows("6:20").EntireRow.Hidden = True
Rows("21:25").EntireRow.Hidden = False
End Select
Select Case Michael
Case Is = "Michael"
Rows("1:5").EntireRow.Hidden = True
Rows("6:25").EntireRow.Hidden = False
End Select
End Sub
I created a dummy test Excel worksheet and inserted your VBA code into a new module. It worked fine for me, albeit is a bit clunky.
Some suggestions to help:
Always set Option Explicit at the top of your module, because this means any undeclared variables and other little things like that get picked up immediately. It's good practice to get into that habit early when starting out with VBA.
Always qualify your .Range statement with the prefix for the specific workbook/worksheet your code needs to work on. This may be why it isn't working for you, but ran fine for me. As it stands, your code will only run on whatever worksheet happens to be active at the time.
You have made this a Private Sub (private subroutine). If you have done the proverbial copy & paste then this subroutine will not show up in your list of macros, which could be another reason you cannot run it. I highly recommend you have a read of this ExcelOffTheGrid article, which breaks down the different types nicely. If you have inserted this into the Worksheet object of your VBA Project, then it may need to be moved into its own Module.
You have assigned three different names (Andrew, Robert, Michael) to the same .Range reference. This shouldn't really be allowed (although weirdly didn't flag an error when I copied your code) because what it is saying is that those text strings - and they could be anything, not just those names - all refer to the same specific cell on your worksheet. This hasn't affected your code, because you don't actually refer to them later on. In your Select Case logical tests you have used double quotes " " around each name, telling VBA it is a string of characters not a variable you have defined.
I would suggest something like this:
COPY & PASTE INTO A NEW MODULE
Option Explicit
'
'
Sub HideRows()
' This macro will hide specific non-contiguous rows based upon criteria in my drop down combo box.
'
Dim wkMyBook As Workbook
Dim wsMainSheet As Worksheet
Dim rName As Range
'
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
Set wkMyBook = ActiveWorkbook
Set wsMainSheet = wkMyBook.Sheets("ENTER SHEET NAME HERE")
Set rName = wsMainSheet.Range("K30")
Select Case rName
Case Is = "Andrew"
wsMainSheet.Rows("8:10").EntireRow.Hidden = True
wsMainSheet.Rows("11:12").EntireRow.Hidden = False
wsMainSheet.Rows("13:13").EntireRow.Hidden = True
wsMainSheet.Rows("14:25").EntireRow.Hidden = False
Case Is = "Robert"
wsMainSheet.Rows("6:20").EntireRow.Hidden = True
wsMainSheet.Rows("21:25").EntireRow.Hidden = False
Case Is = "Michael"
wsMainSheet.Rows("1:5").EntireRow.Hidden = True
wsMainSheet.Rows("6:25").EntireRow.Hidden = False
End Select
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
End Sub
COPY & PASTE INTO THE WORKBOOK OBJECT
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
' This code will run whenever a change is made to your worksheet
If Target.Address = "$K$30" Then
Select Case Target.Value
Case Is = "Andrew", "Robert", "Michael"
Call HideRows
End Select
End If
End Sub
This has bought your ticket, given you the lift, dropped you off right at the door. Now you gotta do that final step to put this together to make it work. Read the article I linked, learn about bit about how VBA is constructed and then next time you should be a bit further along the path before you need a pick up. Good luck!
Drop Down Worksheet Change
When you change a value in a cell via 'drop down', the Worksheet.Change event is triggered.
Copy the first code into the appropriate sheet module e.g. Sheet1.
Copy the second code into a standard module, e.g. Module1.
You do not run anything, it is automatically showing or hiding rows.
Sheet1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RangeAddress As String = "K30"
If Not Intersect(Target, Me.Range(RangeAddress)) Is Nothing Then
manipulateRows Me, Target.Value
End If
End Sub
Module1
Option Explicit
Sub manipulateRows(Sheet As Worksheet, checkString As String)
With Sheet
Select Case checkString
Case "Andrew"
.Rows("8:10").Hidden = True
.Rows(13).Hidden = True
.Rows("11:12").Hidden = False
.Rows("14:25").Hidden = False
Case "Michael"
.Rows("1:5").Hidden = True
.Rows("6:25").Hidden = False
Case "Robert"
.Rows("6:20").Hidden = True
.Rows("21:25").Hidden = False
Case Else ' When DEL is pressed (Empty Cell), shows all rows.
.Rows("1:25").Hidden = False
End Select
End With
End Sub

Autofill cells based on drop down list in excel

I am trying to creata a VBA that gives me automatic values based on drop down list in a form. The problem is that when I run the macro then it is causing an error and excel stops working. Any help in this case is most welcome.
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("$G$11") = "UD Sheet" Then
Rows("20:25").EntireRow.Hidden = False
Else
Rows("21:25").EntireRow.Hidden = True
End If
If Range("G12").Value = "Flex Tape" Then
Range("B20").Value = "None"
Else
Range("B20").Value = ""
End If
exitHandler:
Application.EnableEvents = True
Exit Sub
End Sub
First thing first, in your code, no need to put an Exit Sub before the End Sub.
The code will end after that line so this is a redundancy.
The next thing that you need to understand is that the Change Event will keep triggering if you will not disable it explicitly. So it means that when you hide a row on that Sheet, the Change Event will keep on happening since there will be changes that will happen on the Sheet. i.e. (Hiding Rows).
To do that you need to disable the EventsListeners of the application using the Application.EnableEvents = False. So the application can do a single thing based on that first event.
The next thing that you need to keep in mind is to track where the Changes occur and fire your program. Target is a Range Object that will return the Range where the specific change occurs on the Sheet.
In order to do that, you need to validate if you need to trigger the routine based on the target using the Intersect function.
The whole code is as follows:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Not Intersect(Target, Range("G11")) Is Nothing Then
If Range("$G$11") = "UD Sheet" Then
Rows("20:25").EntireRow.Hidden = False
Else
Rows("21:25").EntireRow.Hidden = True
End If
End If
If Not Intersect(Target, Range("G12")) Is Nothing Then
If Range("G12").Value = "Flex Tape" Then
Range("B20").Value = "None"
Else
Range("B20").Value = ""
End If
End If
Application.EnableEvents = True
End Sub

Issue Combining Worksheet_Change subs (Invalid or Unqualified Reference Error)

I have a project that uses a Worksheet_Change sub to make certain images visible or invisible based on the value of a particular cell (in this case B23).
Now I'm trying to add a second criteria to make a different set of images visible/invisible based on the value in a different cell (in this case B24).
The problem is that I'm now getting a "Invalid or Unqualified Reference" Error, and it looks like it has to do with the ".pictures" piece. Here is the code I'm trying to run:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("$B$23,$B$24")) Is Nothing Then Exit Sub
If Target.Address = "$B$23" Then
Select Case Target.Value
Case "driving"
.Pictures("Auto_Map_Labeled").Visible = True
.Pictures("Bicycle_Map_Labeled").Visible = False
.Pictures("Pedestrian_Map_Labeled").Visible = False
Case "bicycling"
.Pictures("Auto_Map_Labeled").Visible = False
.Pictures("Bicycle_Map_Labeled").Visible = True
.Pictures("Pedestrian_Map_Labeled").Visible = False
Case "walking"
.Pictures("Auto_Map_Labeled").Visible = False
.Pictures("Bicycle_Map_Labeled").Visible = False
.Pictures("Pedestrian_Map_Labeled").Visible = True
End Select
ElseIf Target.Address = "$B$24" Then
Select Case Target.Value
Case "visible"
.Pictures("Thumbs_Up").Visible = True
Case "invisible"
.Pictures("Thumbs_Up").Visible = False
End Select
End If
End Sub
Any ideas what might be going wrong? I should note that I'm very new to VBA, so looking for the simplest solution possible.

excel vba slowing excel down, causing 10 second egg timer delay when clicking anywhere on sheet

I am using the following vba codes which im using to hide a set of rows and unhide rows depending on if a cell contains text or not, and they are causing my excel spreadsheet to be slow and unresponsive and causing the egg timer to show for about 10 seconds.
If I take the code out It speeds things up so what can I do to my codes to get them to speed up and not take so long? perhaps there is a better way of structuring the code but im really new to vba so am not sure what I would need to do, would appreciate someone's help thanks.
the reason I am using worksheet change and worksheet selection change is so that whether a user clicks on a cell or not the page still updates
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("K22").Value <> "" Then
Application.ScreenUpdating = False
Rows("25:38").EntireRow.Hidden = False
Rows("40:48").EntireRow.Hidden = True
ElseIf Range("K22").Value = "" Then
Rows("25:38").EntireRow.Hidden = True
Rows("40:48").EntireRow.Hidden = False
End If
Application.ScreenUpdating = True
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("K22").Value <> "" Then
Application.ScreenUpdating = False
Rows("25:38").EntireRow.Hidden = False
Rows("40:48").EntireRow.Hidden = True
ElseIf Range("K22").Value = "" Then
Rows("25:38").EntireRow.Hidden = True
Rows("40:48").EntireRow.Hidden = False
End If
Application.ScreenUpdating = True
End Sub
The main issue is from the Worksheet_Change event, but it could be applied to any event.
The worksheet change is triggering each time you hide a column, so it's trying several times to hide the same columns, before (eventually) failing with an out of memory error:
Hide these columns... Oh, a worksheet change... Hide these columns... Oh, A worksheet change... Hide th...
To avoid this, you need to use
Application.EnableEvents = False
when you decide you are going to make changes, and
Application.EnableEvents = True
when done.
You may also want to put some error handling that turns the events on again, as if something else occurs that stops the code from running, the triggers will be turned off, and the spreadsheet will no longer update as you expect it to.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
Application.EnableEvents = False
If Range("K22").Value <> "" Then
Rows("25:38").Hidden = False
Rows("40:48").Hidden = True
Else
Rows("25:38").Hidden = True
Rows("40:48").Hidden = False
End If
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
This works instantly for me:
Application.ScreenUpdating = False
Select Case Range("K22")
Case Is <> ""
Rows("25:38").Hidden = False
Rows("40:48").Hidden = True
Case Else
Rows("25:38").Hidden = True
Rows("40:48").Hidden = False
End Select
Application.ScreenUpdating = True

Resources