So I've set up a conditional formatting VBA macro to highlight two cells: The one with the given string, and the one next to it.
The data set is:
A1 B1
------------------------
PluginID NUM
Host ADDRESS
Severity High
Port PORT
Description DESCRIPTION
Solution SOLUTION
References CVE
The VBA code is:
Sub High2()
'
' High2 Macro
'
'
Columns("A:B").Select
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=AND($B1=""High"",A1)"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
End Sub
This highlights the cell with 'High' in it, and the cell to the left, 'Severity'.
If I change the "=AND($B1=""High"",A1)" line to "=AND($B2=""High"",A1)" then excel will highlight the 2 cells above it in red instead, i.e. Host.
Can anyone help me with highlighting the 4 cells above and 8 cells below the string search-term as well (i.e. the Port, Description, Solution and References cells)?
What you are actual doing if you "change the "=AND($B1=""High"",A1)" line to "=AND($B2=""High"",A1)"" is simply add a new rule. So this will be really the best approach. Adding as much rules as necessary.
Sub High2()
With Columns("A:B").Cells
.Range("A1").Activate
.FormatConditions.Delete
For i = 1 To 3 ' 3 above
.FormatConditions.Add Type:=xlExpression, Formula1:="=($B" & i & "=""High"")"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
Next
For i = 0 To 3 ' 4 below
.FormatConditions.Add Type:=xlExpression, Formula1:="=($B" & .Rows.Count - i & "=""High"")"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
Next
End With
End Sub
This could also be reached with only one rule:
=OR($B1048573:$B1048576="High", $B1:$B3="High")
But this will lead to bad performance since it is working as an array formula.
Related
I'm trying to create a VBA Macro to automate part of a large process. I can do it manually but it isn't practical as there are 27K rows.
I have a range of dates in columns F through AC. I'm trying to use conditional formatting to color the ones that fall between the dates in columns A and B on the same row. IE: Row 2 (1 is headers) A2 and B2 are dates that span one year. F2:AC2 are filled with dates that may or may not fall in that range. Turn the ones that do red (pink red text or what ever). Continue for the next 27K rows.
What I have is working on a 57 item sample Except that it only references the original hard coded selections from the macro recording. I'm struggling with the syntax to make it dynamic.
[code]Sub Conditions()
'
' Conditional format
'
Dim x As Integer
Application.ScreenUpdating = False
NumRows = Range("F2", Range("F2").End(xlDown)).Rows.Count
'Range("F2").Select
'Range(("F2"), Selection.End(xlToRight)).Select
Range("F2").Select
Range(("F2"), Selection.End(xlToRight)).Select
For x = 1 To NumRows
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlBetween, _
Formula1:="=$A$2", Formula2:="=$B$2"
'Formula1:="=ActiveCell.Offset(0,-5)", Formula2:="=ActiveCell.Offset(0,-4)" '<---- offset from active cell
Selection.FormatConditions (Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13551615
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
ActiveCell.Offset(1, 0).Select
Range(ActiveCell, ActiveCell.End(xlToRight)).Select
Next
Application.ScreenUpdating = True
End Sub [code]
Any help is appreciated.
this worked perfectly.
Sub Conditions2()
Dim numrows As Long
Range("F2").Select
numrows = Range("F2", Range("F2").End(xlDown)).Rows.Count
With Range("F2", Range("F2").End(xlToRight)).Resize(numrows)
With .FormatConditions.Add(Type:=xlCellValue, Operator:=xlBetween, Formula1:="=$A2", Formula2:="=$B2")
.SetFirstPriority
With .Font
.Color = -16383844
.TintAndShade = 0
End With
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 13551615
.TintAndShade = 0
End With
.StopIfTrue = False
End With
End With
End Sub
I am trying to have my macro sort my data based on the result of an IFERROR function in column A and the cell color in column B.
In column A, the IFERROR is performing a VLOOKUP on another workbook to check for matching values. Column A is highlighted Red by default, along with a bunch of other previously highlighted cells in the master workbook.
So basically, this is what I'm trying to make happen:
If column A passes IFERROR function AND is highlighted Red AND column B has No Fill, then select the entire row. I would like this to check the entire workbook.
Please forgive me if I am not making much sense, I'm having a difficult time putting this into words.
I figured it out.
`
Range("A2:AH2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.FormatConditions.Add Type:=xlExpression, Formula1:="=ISERROR(A2)"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=ISNUMBER($A2)"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 5287936
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False`
Since each row has to be evaluated individually, you are going to have each two cell combination.
For i = 2 to lastrow
If Range("A" & i).Interior.ColorIndex = RGB(255, 0, 0) And Range("B" & i).Interior.ColorIndex = xlNone And Not Application.WorksheetFunction.IsError(Range("A" & i)) Then
'do your code if all are true
end if
Next i
I am extremely new to VBA world and need some assistance with the VBA side of conditional formatting.
1) I need conditional formatting to be applied to column (M)
green under 7
yellow from 7-20
red greater than 20
With the overriding condition that if column (N) if it states NOPO, I do not want conditional formatting to be applied.
I have worked out a formula to use that indicates what colour is required but unable to turn that into VBA conditional formatting (this formula shows what colour and if the conditional formatting should be applied.
=IF(N2="osno",IF(M2<=7,"green",IF(M2<7,IF(M2>20,"red","less than 20"),IF(M2>20,IF(M2>20,"red","less than 20"),"yellow"))),"no format")
This is my current VBA script, as you can no doubt see it's very messy and was from a recorded script.
Sub Conditional()
'
' Notification_05 Macro
' Conditional Formatting
'
'
Sheets("Final").Select
Columns("M:M").Select
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlLess, _
Formula1:="=8"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 5296274
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlBetween, _
Formula1:="=8", Formula2:="=20"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 49407
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreater, _
Formula1:="=20"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 470000
.TintAndShade = 0
ActiveWindow.SmallScroll Down:=-27
Range("M2").Select
With Range("M:M")
.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=LEN(TRIM(M1))=0"
With .FormatConditions(.FormatConditions.Count)
.SetFirstPriority
End With
End With
End With
End Sub
Thanks,
Blake
A CF formula needs to return either true or false: you can't use a single formula to assign one of multiple colors, only to decide if a color should be applied or not. You will need three rules, each with a slightly different formula.
Sub Tester()
Dim rng As Range
Set rng = Selection
rng.FormatConditions.Delete 'clear any existing rules
AddRule rng, "=AND(M2=""osno"", N2<7)", vbGreen
AddRule rng, "=AND(M2=""osno"", N2>=7,N2<=20)", vbYellow
AddRule rng, "=AND(M2=""osno"", N2>20)", vbRed
End Sub
'utility sub: add a CF rule given the formula and a fill color
Sub AddRule(rng, sFormula, lColor)
With Selection.FormatConditions
With .Add(Type:=xlExpression, Formula1:=sFormula)
.Interior.Color = lColor
.StopIfTrue = True
End With
End With
End Sub
I'm creating an Excel document at runtime that has a bunch of values I'd like to have conditionally formatted. In going through various attempts from scratch as well as using/modifying code outputted from the Excel's macro recorder, I'm having a consistent issue related to formatting overwrites.
I've posted a snippet of the code below and can say that I've tested to ensure my selection ranges are valid and appropriate for what I want conditionally formatted. There is some overlap but what's bizarre is that the first conditional format takes on just one property of the second conditional format. Meaning D5:End of the worksheet ends up having a green color font as opposed to the red it should be. Commenting each section of the code does allow them to work independently but I'm guessing this is an issue with specifying conditional formats further somehow? I've tried a few different case scenarios and below is the code with modifications:
EDIT (Updated Code):
'First conditional format, check sheet for values > 50 and make text red.
With xl.range("D5:" & theLastColumn & lastRow)
.FormatConditions.add Type:=xlCellValue, Operator:=xlGreater, Formula1:="=50"
With .FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
'Second conditional format, check specific row (row 5 in the example)
'for values > 40, and fill interior with green in addition to dark green text.
With xl.range("D" & Infectivity & ":" & theLastColumn & Infectivity)
.FormatConditions.add Type:=xlCellValue, Operator:=xlGreater, Formula1:="=40"
With .FormatConditions(2).Font
.Color = -16752384
.TintAndShade = 0
End With
With .FormatConditions(2).Interior
.PatternColorIndex = xlAutomatic
.Color = 13561798
.TintAndShade = 0
End With
End With
So what's the best way to have multiple conditional formats (that may overlap ranges) and still have them all function as intended? I've tried debugging this so much I'm certain there's something easy I'm overlooking. I've also tried a few different methods to specify separate formatconditions(1) and formatconditions(2) but still receive strange issues.
EDIT:
VBA Code where I continue to have the same issue.
Sub conditionalFormat()
With Range("D5:BA9")
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreater, Formula1:="=50"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
With Range("D9:BA9")
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreater, Formula1:="=40"
With .FormatConditions(2).Font
.Color = -16752384
.TintAndShade = 0
End With
With .FormatConditions(2).Interior
.PatternColorIndex = xlAutomatic
.Color = 13561798
.TintAndShade = 0
End With
.FormatConditions(2).StopIfTrue = False
End With
End Sub
Even with the SetFirstPriority on the appropriate (red text) conditional format, it just gets overwritten somehow. Am I missing something here?
Sorry. I don't have Excel 2007. Tested this in Excel 2010.
When it comes to conditional formatting, you have to be really careful of what the macro recorder spits out. This is one particular case where it makes a mess of the code.
Also you are setting then 2nd rule as .SetFirstPriority which is incorrect besides letting the 2nd rule run in spite of rule 1 get getting satisfied :)
Here is a very basic example. Let's say my range looks like this D5:G7
Now this is the VBA code that I tested
Sub Sample()
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Sheet1")
Set rng = ws.Range("D5:G7")
With rng
.FormatConditions.Add Type:=xlCellValue, _
Operator:=xlGreater, Formula1:="=50"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1).Font
.Color = -16776961
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = True
.FormatConditions.Add Type:=xlCellValue, _
Operator:=xlGreater, Formula1:="=40"
With .FormatConditions(2).Font
.Color = -11489280
.TintAndShade = 0
End With
With .FormatConditions(2).Interior
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent3
.TintAndShade = 0.599963377788629
End With
End With
End Sub
And this is the result that I got.
I am sure it will be very easy for you to port the above code to vb6.
FOLOWUP (From Comments)
Using latebinding... would earlybinding be better suited for doing this type of conditional formatting? – Bernard 2 mins ago
If you are using LateBinding then declare this code at the top of your code
Const xlCellValue as Long = 1
Const xlGreater as Long = 5
Const xlAutomatic as Long = -4105
Const xlThemeColorAccent3 as Long = 7
After much thought and reworking the code we came to the conclusion that what I was doing (multiple conditions overlapping) was the cause of the mixed results. At the simplest level, I was able to add .FormatConditions.Delete to my additional conditional formats to ensure only one format was applied.
The corrected final code is shown below:
Dim Infectivity As Long
Infectivity = Application.WorksheetFunction.match("Infectivity", range("A1:" & "A" & lastRow), 0)
With xl.range("D5:" & theLastColumn & lastRow)
.FormatConditions.add Type:=xlCellValue, Operator:=xlGreater, _
Formula1:="=50"
.FormatConditions(.FormatConditions.count).SetFirstPriority
With .FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
If Infectivity > 0 Then
With xl.range("D" & Infectivity & ":" & theLastColumn & Infectivity)
.FormatConditions.Delete
.FormatConditions.add Type:=xlCellValue, Operator:=xlGreater, _
Formula1:="=40"
With .FormatConditions(1).Font
.Color = -16752384
.TintAndShade = 0
End With
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13561798
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
End If
My downfall was related to the macro recorder giving me a false of the ideal method of formatting these cells. It's always best to simplify before moving forward.
Major thanks to Siddharth Rout for all the help.
I'm trying to do conditional formatting on a long range of columns in groups of 2. Im not sure how record a macro that would select the entire column from the active cell and the column next to it, then apply the conditional formating. Then move two cells down and repeat.
This is what I have so far but it would keep going back to those specific cells, I need it to move to the right 2.
Sub findDups()
'
' findDups Macro
ActiveCell.EntireColumn.Select
Selection.FormatConditions.AddUniqueValues
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
Selection.FormatConditions(1).DupeUnique = xlDuplicate
With Selection.FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13551615
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Range("M1").Select
Worksheets("User Check List").Activate
Selection.Offset(0, 2).Select
End Sub
This should work to get you started. I avoid using Selection at all, and only use ActiveCell as a means of knowing where to start the macro. Preferably, you could do that with an Application.InputBox but that's not a big deal.
Because I don't know how many times you want this to loop, I used a Do ... Loop statement, and this will continue until the column number > 26. You can change that in the Loop Until ... statement.
Sub findDups()
Dim startCell As Range
Dim formatCols As Range
Set startCell = ActiveCell
Do
Set formatCols = startCell.Resize(1, 2).EntireColumn
formatCols.FormatConditions.AddUniqueValues
formatCols.FormatConditions(formatCols.FormatConditions.Count).SetFirstPriority
formatCols.FormatConditions(1).DupeUnique = xlDuplicate
With formatCols.FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
With formatCols.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13551615
.TintAndShade = 0
End With
Set startCell = startCell.Offset(0, 2)
Loop Until startCell.Column >= 26
End Sub
Here is an example of the output formatting: