Combine two Worksheet_Change Subs - excel

I need two actions to take place on one sheet in my workbook. Both are based on a change event, but do not know how to make them both work. Below is the codes that I have:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range
Set r = Target.EntireRow
If Target.row = 1 Then Exit Sub ' Don't change header color
If r.Cells(1, "AD").Value <> "" Then
r.Font.Color = RGB(0, 176, 80)
Else
r.Font.ColorIndex = 1
End If
End Sub
And this one:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range
Set r = Target.EntireRow
If Target.row = 1 Then Exit Sub ' Don't change header color
If r.Cells(1, "E").Value = "6" Then
r.Font.Color = RGB(255, 0, 0)
Else
r.Font.ColorIndex = 1
End If
End Sub
To help determine the best course of action, here is what the end results must be:
For any row that has a date entered into cell AD, the text color for the entire row should change to green. However, if cell E of any row contains a 6 (this is a number formatted as text), then the text in that row should be red.
I am sure that I am over thinking this. All suggestions are appreciated.

Use an And in your first If statement, and add an ElseIf statements.
I am not exactly sure what you want to take precedence if both a date and 6 exist or if there is one without the other, but you can easily adjust the If Then ElseIf block below to sort out your needs.
If r.Cells(1, "AD").Value <> "" And r.cells(1,"E").Value = "6" Then
r.Font.Color = RGB(255, 0, 0)
ElseIf r.Cells(1,"AD").Value <> "" Then
r.Font.Color = RGB(0, 176, 80)
Else
r.Font.ColorIndex = 1
End If

Related

Yes/No boxes in VBA

I have an array of shapes created in a for loop and want to assign simple code to each of them as "yes/no" buttons.
The code that creates the array of buttons is as follows:
Dim i As Integer
Dim j As Integer
Dim k As Integer
For i = 1 To 3
For j = 2 To 17
ActiveSheet.Shapes.addshape(msoShapeRectangle, Cells(j, i).Left + 0, _
Cells(j, i).Top + 0, Cells(j, i).Width, Cells(j, i).Height).Select
Next j
Next i
I would like to be able to assign code to each of the shapes as they are created but do not know how. What I want the code to do for each shape looks like the below. I want the shapes to react when clicked and cycle through yes/no/blank text in each of the shapes. The general logic of the code is below
value = value +1
if value = 1, then "yes" and green
if value = 2, then "no" and red
if value = 3, then value = 0 and blank and grey
Thank you in advance for your help
You can do something like this:
Option Explicit
Sub Tester()
Dim i As Long, j As Long, k As Long
Dim addr As String, shp As Shape
For i = 1 To 3
For j = 2 To 17
With ActiveSheet.Cells(j, i)
Set shp = .Parent.Shapes.AddShape(msoShapeRectangle, .Left + 0, _
.Top + 0, .Width, .Height)
With shp.TextFrame2
.VerticalAnchor = msoAnchorMiddle
.TextRange.ParagraphFormat.Alignment = msoAlignCenter
End With
shp.Name = "Button_" & .Address(False, False)
End With
shp.Fill.ForeColor.RGB = RGB(200, 200, 200)
shp.OnAction = "ButtonClick"
Next j
Next i
End Sub
'called from a click on a shape
Sub ButtonClick()
Dim shp As Shape, capt As String, tr As TextRange2
'get a reference to the clicked-on shape
Set shp = ActiveSheet.Shapes(Application.Caller)
Set tr = shp.TextFrame2.TextRange
Select Case tr.Text 'decide based on current button text
Case "Yes"
tr.Text = ""
shp.Fill.ForeColor.RGB = RGB(200, 200, 200)
Case "No"
tr.Text = "Yes"
shp.Fill.ForeColor.RGB = vbGreen
Case ""
tr.Text = "No"
shp.Fill.ForeColor.RGB = vbRed
End Select
End Sub
Just to visualize my idea regarding using the selection change event instead of buttons:
The area that should be the clickable range is named clickArea - in this case B2:D17.
Then you put this code in the according sheet module
Option explicit
Private Const nameClickArea As String = "clickArea"
Private Enum bgValueColor
neutral = 15921906 'gray
yes = 11854022 'green
no = 11389944 'red
End Enum
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'whenever user clicks in the "clickArea" the changeValueAndColor macro is triggered
If Not Intersect(Target.Cells(1, 1), Application.Range(nameClickArea)) Is Nothing Then
changeValueAndColor Target.Cells(1, 1)
End If
End Sub
Private Sub changeValueAndColor(c As Range)
'this is to deselect the current cell so that user can select it again
Application.EnableEvents = False: Application.ScreenUpdating = False
With Application.Range(nameClickArea).Offset(50).Resize(1, 1)
.Select
End With
'this part changes the value and color according to the current value
With c
Select Case .Value
Case vbNullString
.Value = "yes"
.Interior.Color = yes
Case "yes"
.Value = "no"
.Interior.Color = no
Case "no"
.Value = vbNullString
.Interior.Color = neutral
End Select
End With
Application.EnableEvents = True: Application.ScreenUpdating = True
End Sub
And this is how it works - with each click on one of the cells value and background color are changed. You have to click on the image to start anmimation.
To reset everything I added a hyperlink that calls the reset action (and refers to itself)
Add this code to the sheets module
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
clearAll
End Sub
Private Sub clearAll()
With Application.Range(nameClickArea)
.ClearContents
.Interior.Color = neutral
End With
End Sub

Coloring of a referenced cell (Excel, VBA)

If I have a column of referenced numbers and I would like to color the referenced cell automatically after right clicking, how can I refer to the reference cell in VBA. In the exmaple I have the referenced values in column [O]. At [O4] I have the value [=$G$12]. If I click on [O4] I want to color it together with the reference cell G12. It would be an additional step that I would like to color the cell above [G12] as well.
I tried to insert this in the formula:
REPLACE(SUBSTITUTE(FORMULATEXT($O$4),"$",""),1,1,"")
Which would give back the reference cell [G12] in a normal excel sheet without equal sign but the script doesn't work with it.
Thank you for the support in advance!
Select Case Target.Address
Case "$O$4" '<~ if cell A1 is clicked, highlight cells C5-C9 yellow
Cancel = True
If .Range("O4,G11:G12").Interior.Color = RGB(255, 153, 0) Then
.Range("O4,G11:G12").Interior.Color = RGB(255, 255, 255)
.Range("O4,G11:G12").Font.Bold = False
Else: .Range("O4,G11:G12").Interior.Color = RGB(255, 153, 0)
.Range("O4,G11:G12").Font.Bold = True
End If
End Select
you could use Precedents property of Range obejct:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Select Case Target.Address
Case "$O$4"
Cancel = True
Dim rng As Range
Set rng = Target.Precedents
If rng Is Nothing Then
Set rng = Target
Else
Set rng = Union(Target, rng, rng.Offset(-1))
End If
If rng.Interior.Color = RGB(255, 153, 0) Then
rng.Interior.Color = RGB(255, 255, 255)
rng.Font.Bold = False
Else
rng.Interior.Color = RGB(255, 153, 0)
rng.Font.Bold = True
End If
End Select
End Sub
Try this approach, please:
Dim strForm As String, newRng As Range
Select Case Target.Address
Case "$O$4" '<~ if cell A1 is clicked, highlight cells C5-C9 yellow
Cancel = True
strForm = Target.Formula
'split string formula on "$" character and use the array obtained elements, to build the new address
Set newRng = Range(Range(Split(strForm, "$")(1) & Split(strForm, "$")(2) - 1).Address & ":" & _
Range(Split(strForm, "$")(1) & Split(strForm, "$")(2)).Address)
If Range(Target.Address(0, 0) & "," & newRng.Address).Interior.Color = RGB(255, 153, 0) Then
Range(Target.Address(0, 0) & "," & newRng.Address).Interior.Color = RGB(255, 255, 255)
Range(Target.Address(0, 0) & "," & newRng.Address).Font.Bold = False
Else: Range(Target.Address(0, 0) & "," & newRng.Address).Interior.Color = RGB(255, 153, 0)
Range(Target.Address(0, 0) & "," & newRng.Address).Font.Bold = True
End If
End Select
Thank you very much for both of you. Finaly it works. I have an additonal qiestion in order to reduce the length of the code.
Lets consider it as a block for coloring cells if I clcik on [O4] cell. If I dont want to repeate this block many times but I want the same feature for the range of [O4:O45] with corresponding refernce content how I can do that? Sorry I'm not so experenced in coding but I'm very satisfied wth the result so far.
Thanks a lot!

Execute excel VBA macro on cell change doesnt update

I have this code:
Sub CheckRevision()
Dim CurCell As Object
For Each CurCell In ActiveWorkbook.ActiveSheet.Range("B1:B5000")
If CurCell.Value = "Live" Then CurCell.Interior.Color = RGB(0, 204, 0)
Next
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B1:B5000")) Is Nothing Then CheckRevision
End Sub
This works fine, however if I then have a cell which is "live" and change it back to "NOTLIVE" for example, the formatting is still a green cell. How do I get it to put it back to white default?
try: (but have a look art Peh's comment)
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B1:B5000")) Is Nothing Then
For Each cl In Intersect(Target, Me.Range("B1:B5000"))
If UCase(cl.Value) = "LIVE" Then
cl.Interior.Color = RGB(0, 204, 0)
Else
cl.Interior.Color = xlNone
End If
Next
End If
End Sub
Just replace line If CurCell.Value = "Live" Then CurCell.Interior.Color = RGB(0, 204, 0)
with
If curcell.Value = "Live" Then
curcell.Interior.Color = RGB(0, 204, 0)
Else
curcell.Interior.Pattern = xlNone
End If
You don't really need the If statement at all.. you could just use this:
Sub CheckRevision()
Dim CurCell As Object
For Each CurCell In ActiveWorkbook.ActiveSheet.Range("B1:B5000")
CurCell.Interior.Color = xlNone - ((CurCell.Value = "Live") * (RGB(0, 204, 0) - xlNone))
Next
End Sub
So, how does this work? (Thanks, Pᴇʜ)
You're basically attempting to paint a cell with a colour that is either:
xlNone or RGB(0, 204, 0)
-4142 or 52224
This is decided by the CurCell.Value = "Live" which when used this way (cast into an integer) will return either 0 (for False) or -1 (for True).
Knowing that all this decision making results in a little bit of maths allows us to write an equation that causes the 0 or -1 to produce the two values:
If CurCell.Value = "Live" then the equation looks like this:
CurCell.Interior.Color
= xlNone - (-1 * (RGB(0, 204, 0) - xlNone))
... = xlNone - (-1 * (RGB(0, 204, 0) - xlNone))
... = RGB(0, 204, 0)
= 52224
If CurCell.Value <> "Live" then the equation looks like this:
CurCell.Interior.Color = xlNone - (0 * (RGB(0, 204, 0) - xlNone))
... = xlNone - (0 * (RGB(0, 204, 0) - xlNone))
... = xlNone
= -4142
if you aiming to change ONLY value of the cell you change the particular moment you can use the below which does not loop the whole range BUT test only the specific cell.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
'Check if the cell changed included in the range B1:B5000 & if only one cell changed to avoid errors
If Not Intersect(Target, Range("B1:B5000")) Is Nothing And Target.Count = 1 Then
'Call the module to apply formatting passing 3 parameters.
Call Module1.CheckRevision(Target.Worksheet, Target.Value, Target.Address)
End If
End Sub
Sub CheckRevision(wsName As Worksheet, cellValue As String, cellAddress As String)
With wsName.Range(cellAddress)
If cellValue = "Live" Then
.Interior.Color = RGB(0, 204, 0)
Else
.Interior.Pattern = xlNone
End If
End With
End Sub

How do I loop and compare 2 columns in 2 worksheets and reference increase or decrease?

I want to compare 2 columns from 2 different worksheets (The same column in each sheet), then compare if they have increased or decreased, then color the cell red or green to indicate if increased or decreased. However my formula doesn't work...
I tried the columns on the same sheet using activecell, and activecell offset and it worked, but I cant seem to reference it in another sheet?
But is my (unworking) code...
Sub test3()
Range("A1").Select
Do
If ActiveWorkbook.worksheets(“Sheet1!”).Cell(ActiveCell) > ActiveWorkbook.worksheets(“Sheet2!”).Cell(“A1”) Then
ActiveCell.Interior.Color = RGB(255, 0, 0)
ElseIf ActiveWorkbook.worksheets(“Sheet1!”).Cell(ActiveCell) < ActiveWorkbook.worksheets(“Sheet2!”).Cell(“A1”) Then
ActiveCell.Interior.Color = RGB(0, 255, 0)
Else
End If
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell)
End Sub
Try this, just need to set column to whatever column index you need.
Dim row As Integer
Dim column As Integer
row = 1
column = 1
ActiveWorkbook.Worksheets("Sheet1!").Cells.Interior.Color = RGB(255, 255, 255)
Do While ActiveWorkbook.Worksheets("Sheet1!").Cells(row, column) <> ""
If ActiveWorkbook.Worksheets("Sheet1!").Cells(row, column) <> ActiveWorkbook.Worksheets("Sheet2!").Cells(row, column) Then
If ActiveWorkbook.Worksheets("Sheet1!").Cells(row, column) > ActiveWorkbook.Worksheets("Sheet2!").Cells(row, column) Then
ActiveWorkbook.Worksheets("Sheet1!").Cells(row, column).Interior.Color = RGB(255, 0, 0)
Else
ActiveWorkbook.Worksheets("Sheet1!").Cells(row, column).Interior.Color = RGB(0, 255, 0)
End If
End If
row = row + 1
Loop
This will work - just change the colorRng reference to suit your needs:
Sub ColorCode()
Dim cl As Range, colorRng As Range
Set colorRng = Worksheets(1).Range("A1:A10")
For Each cl In colorRng
If cl > Worksheets(2).Cells(cl.Row, cl.Column) Then
cl.Interior.Color = RGB(255, 0, 0)
Else
cl.Interior.Color = RGB(0, 255, 0)
End If
Next cl
End Sub

VBA macro to compare two columns and color highlight cell differences

I wanted to color highlight cells that are different from each other; in this case colA and colB. This function works for what I need, but looks repetitive, ugly, and inefficient. I'm not well versed in VBA coding; Is there a more elegant way of writing this function?
EDIT
What I'm trying to get this function to do is:
1. highlight cells in ColA that are different or not in ColB
2. highlight cells in ColB that are different or not in ColA
Sub compare_cols()
Dim myRng As Range
Dim lastCell As Long
'Get the last row
Dim lastRow As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
'Debug.Print "Last Row is " & lastRow
Dim c As Range
Dim d As Range
Application.ScreenUpdating = False
For Each c In Worksheets("Sheet1").Range("A2:A" & lastRow).Cells
For Each d In Worksheets("Sheet1").Range("B2:B" & lastRow).Cells
c.Interior.Color = vbRed
If (InStr(1, d, c, 1) > 0) Then
c.Interior.Color = vbWhite
Exit For
End If
Next
Next
For Each c In Worksheets("Sheet1").Range("B2:B" & lastRow).Cells
For Each d In Worksheets("Sheet1").Range("A2:A" & lastRow).Cells
c.Interior.Color = vbRed
If (InStr(1, d, c, 1) > 0) Then
c.Interior.Color = vbWhite
Exit For
End If
Next
Next
Application.ScreenUpdating = True
End Sub
Ah yeah that's cake I do it all day long. Actually your code looks pretty much like the way I'd do it. Although, I opt to use looping through integers as opposed to using the "For Each" method. The only potential problems I can see with your code is that ActiveSheet may not always be "Sheet1", and also InStr has been known to give some issues regarding the vbTextCompare parameter. Using the given code, I would change it to the following:
Sub compare_cols()
'Get the last row
Dim Report As Worksheet
Dim i As Integer, j As Integer
Dim lastRow As Integer
Set Report = Excel.Worksheets("Sheet1") 'You could also use Excel.ActiveSheet _
if you always want this to run on the current sheet.
lastRow = Report.UsedRange.Rows.Count
Application.ScreenUpdating = False
For i = 2 To lastRow
For j = 2 To lastRow
If Report.Cells(i, 1).Value <> "" Then 'This will omit blank cells at the end (in the event that the column lengths are not equal.
If InStr(1, Report.Cells(j, 2).Value, Report.Cells(i, 1).Value, vbTextCompare) > 0 Then
'You may notice in the above instr statement, I have used vbTextCompare instead of its numerical value, _
I find this much more reliable.
Report.Cells(i, 1).Interior.Color = RGB(255, 255, 255) 'White background
Report.Cells(i, 1).Font.Color = RGB(0, 0, 0) 'Black font color
Exit For
Else
Report.Cells(i, 1).Interior.Color = RGB(156, 0, 6) 'Dark red background
Report.Cells(i, 1).Font.Color = RGB(255, 199, 206) 'Light red font color
End If
End If
Next j
Next i
'Now I use the same code for the second column, and just switch the column numbers.
For i = 2 To lastRow
For j = 2 To lastRow
If Report.Cells(i, 2).Value <> "" Then
If InStr(1, Report.Cells(j, 1).Value, Report.Cells(i, 2).Value, vbTextCompare) > 0 Then
Report.Cells(i, 2).Interior.Color = RGB(255, 255, 255) 'White background
Report.Cells(i, 2).Font.Color = RGB(0, 0, 0) 'Black font color
Exit For
Else
Report.Cells(i, 2).Interior.Color = RGB(156, 0, 6) 'Dark red background
Report.Cells(i, 2).Font.Color = RGB(255, 199, 206) 'Light red font color
End If
End If
Next j
Next i
Application.ScreenUpdating = True
End Sub
Things I did differently:
I used my integer method described above (as opposed to the 'for each' method).
I defined the worksheet as an object variable.
I used vbTextCompare instead of its numerical value in the InStr function.
I added an if statement to omit blank cells. Tip: Even if only one
column in the sheet is extra long (e.g., cell D5000 was accidentally
formatted), then the usedrange for all columns is considered 5000.
I used rgb codes for the colors (it's just easier for me since I
have a cheat sheet pinned to the wall next to me in this cubicle
haha).
Well that about sums it up. Good luck with your project!
'Compare the two columns and highlight the difference
Sub CompareandHighlight()
Dim n As Integer
Dim valE As Double
Dim valI As Double
Dim i As Integer
n = Worksheets("Indices").Range("E:E").Cells.SpecialCells(xlCellTypeConstants).Count
Application.ScreenUpdating = False
For i = 2 To n
valE = Worksheets("Indices").Range("E" & i).Value
valI = Worksheets("Indices").Range("I" & i).Value
If valE = valI Then
Else:
Worksheets("Indices").Range("E" & i).Font.Color = RGB(255, 0, 0)
End If
Next i
End Sub
' I hope this helps you

Resources