Excel images to appear based on cell value - excel

I have 2 sheets on excel, one called Raw and one called Graphs. What I want to do is have some cells in Raw and it they =TRUE then I want a shape to appear on the Graphs page.
I am pretty new to VBA so i havent tried much :(
Private Sub Worksheet_Calculate()
With Worksheets("Graph")
If Me.Range("FK45").Value = True Then
.Shapes("Test1").Visible = True
Exit Sub
ElseIf Me.Range("FK45").Value = False Then
.Shapes("Test1").Visible = False
Exit Sub
End If
End With
End Sub
I can get this to work so if FK45 is TRUE the image shows but if FK45 is FALSE it doesn't, But what I want to be able to do is add more to this e.g.
Private Sub Worksheet_Calculate()
With Worksheets("Graph")
If Me.Range("FK45").Value = True Then
.Shapes("Test1").Visible = True
Exit Sub
ElseIf Me.Range("FK45").Value = False Then
.Shapes("Test1").Visible = False
Exit Sub
End If
End With
With Worksheets("Graph")
If Me.Range("FK46").Value = True Then
.Shapes("Test2").Visible = True
Exit Sub
ElseIf Me.Range("FK46").Value = False Then
.Shapes("Test2").Visible = False
Exit Sub
End If
End With
End Sub
I want them all to be independent from each other and be able to add more if necessary
If FK45 is TRUE Image1 shows
If FK45 is FALSE Image1 doesn't show
and/or
If FK46 is TRUE Image2 shows
If FK46 is FALSE Image2 doesn't show
and/or
If FK47 is TRUE Image3 shows
If FK47 is FALSE Image3 doesn't show
and so on...

This is how I would do it
In VB Editor find your Worksheet and Shape objects and rename their system name to something intutive in their respective property windows.
This way you can get rid of With Worksheets("Graph") construction, instead you can call them by their system name like With Graph. This will also come in handy if you wish to rename your worksheets or shapes.
Note that you Exit Sub after each cell check, your procedure stops after first cell and doesn't proceed any further.
Instead of Worksheet.Calculate event I advise using Worksheet.Change. This way you can iterate through your cells one by one.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngCell As Range
Dim shpImage As Shape
For Each rngCell In Target.Cells
' check if change was made in "FK"
If Not Intersect(rngCell, Me.Columns("FK")) Is Nothing Then
Select Case rngCell.Row
Case 45: Set shpImage = Graph.MyImage_1
Case 46: Set shpImage = Graph.MyImage_2
End Select
' if only boolean values present, no need for IF construction
shpImage.Visible = rngCell.Value : Set shpImage = Nothing
End If
Next
End Sub
If you had separate column for image name it would be much easier, you could check like this (for example, shape names are located in "FL" column)
Graph.Shapes(rngCell.Offset(0, 1).Value).Visible = rngCell.Value

Related

Hide Entire given rows if a specified cell is blank

I am a newbie in VBA coding.
I am trying to achieve that inside my function
sub Private Sub Worksheet_Change(ByVal Target As Range)
where it checks some specified cells value change to run a given macro. The additional macro that i want to add is that when ever cell a62 is Empty, it will hide rows a56:a61. and consecutively if a82 is empty, it will hide rows a78:a82.
i have the following code but it only hides the rows from the first empty cell until end of sheet.
Sub Test()
Dim i As Long
For i = 4 To 800
If Sheets("Results").Cells(i, 1).Value = "" Then
Rows(i & ":" & Rows.Count).EntireRow.Hidden = True
Rows("1:" & i - 1).EntireRow.Hidden = False
Exit Sub
End If
Next
End Sub
Please, check the next event code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$62" Or Target.Address = "$A$82" Then
Select Case Target.Address
Case "$A$62"
If Target.Value = "" Then
Range("A56:A61").EntireRow.Hidden = True
Else
Range("A56:A61").EntireRow.Hidden = False
End If
Case "$A$82"
If Target.Value = "" Then
Range("A78:A81").EntireRow.Hidden = True
Else
Range("A78:A81").EntireRow.Hidden = False
End If
End Select
End If
End Sub
It will be triggered only if you MANUALLY change the value of one of the two required cells.
If their value is the result of a formula, Worksheet_Calculate event must be used, but in a different way. This event does not have any argument (no Target) and you must check the two cells in discussion and act according to their value, independent if they were changed or not when the Calculate event is triggered. If this is the case, I can post such an event code, too.
Edited:
For the version which does not involve the manual changing of the values, please copy this event code in the sheet code module:
Private Sub Worksheet_Calculate()
If Me.Range("A62").Value = "" Then
Me.Range("A56:A61").EntireRow.Hidden = True
Else
Me.Range("A56:A61").EntireRow.Hidden = False
End If
If Me.Range("A82").Value = "" Then
Me.Range("A78:A82").EntireRow.Hidden = True
Else
Me.Range("A78:A82").EntireRow.Hidden = False
End If
'Edited:
'The part for both analyzed ranges being empty:
If Me.Range("A62").Value = "" And _
Me.Range("A82").Value = "" Then
'Do here what you need...
End If
End Sub

How to apply code to all the following rows

I have this code but it only work for my first row.
It is suppose to look if the checkbox on B, C or D is checked, and if so, a date + username will automaticaly fill in F and G.
here is a picture of my table:
This is what my code looks like:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("B2") Or Range("C2") Or Range("D2") = True Then
Range("G2").Value = Environ("Username")
Range("F2").Value = Date
Else
Range("F2:G2").ClearContents
End If
End Sub
Enter this code in a regular module, select all your checkboxes and right-click >> assign macro then choose ReviewRows.
This will run the check whenever a checkbox is clicked - a bit of overhead since all rows will be checked, but should not be a big deal.
Sub ReviewRows()
Dim n As Long
For n = 1 To 100 'for example
With Sheet1.Rows(n)
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
Next n
End Sub
If you want to be more precise then Application.Caller will give you the name of the checkbox which was clicked, and you can use that to find the appropriate row to check via the linkedCell.
Sub ReviewRows()
Dim n As Long, shp As CheckBox, c As Range, ws As Worksheet
Set ws = ActiveSheet
On Error Resume Next 'ignore error in case calling object is not a checkbox
Set shp = ActiveSheet.CheckBoxes(Application.Caller) 'get the clicked checkbox
On Error GoTo 0 'stop ignoring errors
If Not shp Is Nothing Then 'got a checkbox ?
If shp.LinkedCell <> "" Then 'does it have a linked cell ?
With ws.Range(shp.LinkedCell).EntireRow
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
End If 'has linked cell
End If 'was a checkbox
End Sub
However this appraoch is sensitive to the exact positioning of your checkbox
You have a long way to go!
Unfortunately, If Range("B2") Or Range("C2") Or Range("D2") = True Then is beyond repair. In fact, your entire concept is.
Start with the concept: Technically speaking, checkboxes aren't on the worksheet. They are on a layer that is superimposed over the worksheet. They don't cause a worksheet event, nor are they responding to worksheet events. The good thing is that they have their own.
If Range("B2") Or Range("C2") Or Range("D2") = True Then conflates Range with Range.Value. One is an object (the cell), the other one of the object's properties. So, to insert sense into your syntax it would have to read, like, If Range("B2").Value = True Or Range("C2").Value = True Or Range("D2").Value = True Then. However this won't work because the trigger is wrong. The Worksheet_Change event won't fire when when a checkbox changes a cell's value, and the SelectionChange event is far too common to let it run indiscriminately in the hope of sometimes being right (like the broken clock that shows the correct time twice a day).
The answer, therefore is to capture the checkbox's click event.
Private Sub CheckBox1_Click()
If CheckBox1.Value = vbTrue Then
MsgBox "Clicked"
End If
End Sub
Whatever you want to do when the checkbox is checked must be done where it now shows a MsgBox. You can also take action when it is being unchecked.

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

Activate macro automatically without having to click on target cell

I have a macro that hides certain rows when the values in a cell change. However this macro is not running unless you enter the target cell and click on it. I have tried several alternatives but none work for me.
Sheet
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("$b$156").Value = 1 Then Call oculta_4
If Range("$b$156").Value = 2 Then Call oculta_5
If Range("$b$156").Value = 3 Then Call oculta_6
If Range("$b$156").Value = 4 Then Call oculta_7
End Sub
Macro
Sub oculta_4()
Rows("158:176").EntireRow.Hidden = False
Range("$c$158").Select
For Each celda In Range("$c$158:$c$176")
If celda.Value = 0 Then
ActiveCell.EntireRow.Hidden = True
End If
ActiveCell.Offset(1).Select
Next
End Sub
As others have said, to respond to a value changed by a Formula, you need to use Worksheet_Calculate.
As Worksheet_Calculate does not have a Target property, you need to create your own detection of certain cells changing. Use a Static variable to track last value.
You should also declare all your other variables too.
Repeatedly referencing the same cell is slow and makes code more difficult to update. Put it in a variable once, and access that
Select Case avoids the need to use many If's
Don't use Call, it's unnecessary and obsolete.
Adding Application.ScreenUpdating = False will make your code snappy, without flicker
Writing the hidden state of a row takes a lot longer than reading it. So only write it if you need to.
Something like this (put all this code in the code-behind your sheet (that's Hoja1, right?)
Private Sub Worksheet_Calculate()
Static LastValue As Variant
Dim rng As Range
Set rng = Me.Range("B156")
If rng.Value2 <> LastValue Then
LastValue = rng.Value2
Select Case LastValue
Case 1: oculta_4
Case 2: oculta_5
Case 3: oculta_6
Case 4: oculta_7
End Select
End If
End Sub
Sub oculta_4()
Dim celda As Range
Application.ScreenUpdating = False
For Each celda In Me.Range("C158:C176")
With celda.EntireRow
If celda.Value = 0 Then
If Not .Hidden Then .Hidden = True
Else
If .Hidden Then .Hidden = False
End If
End With
Next
Application.ScreenUpdating = True
End Sub

Resources