Conditional Formatting Excel VBA - excel

Hi, every day i have to update an excel file. This includes formatting column B. (see picture above). I haven't found VBA code yet, to geht this kind of formatting via VBA. in the picture you see a subset of formatting rules, there are more. But there is only those three colors, which I have the hex code.
yellow
#9C5700
red
#9C0006
green
#006100
' (1) Highlight defined good as green values
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "=2")
.Interior.ColorIndex = 6
.StopIfTrue = False
End With
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "in Anfrage")
.Interior.ColorIndex = 6
.StopIfTrue = False
End With
' (2) Highlight defined ok as yellow values
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "=1")
.Interior.ColorIndex = 4
.StopIfTrue = False
End With
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "ok")
.Interior.ColorIndex = 4
.StopIfTrue = False
End With
' (2) Highlight defined bad as red values
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "=3")
.Interior.ColorIndex = 3
.StopIfTrue = False
End With
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "kritisch")
.Interior.ColorIndex = 3
.StopIfTrue = False
End With
End Sub
I used this code, but i would like to use the hex colors. How do I use those?

Per this Article:
You can assign the color codes to any Color property of any object in either their decimal or hex representation. Precede the Hex value with the &H prefix
However for some reason VBA does swap the first two characters with the last two characters of a hex code, so your Yellow 9C7500 would go into VBA as 00759C
So, instead of .Interior.ColorIndex, use .Interior.Color and put in your hex codes with &H at the start.
Example:
' (1) Highlight defined good as green values
With Range("b:b").FormatConditions.Add(xlCellValue, xlEqual, "=2")
.Interior.Color = &H006100
.StopIfTrue = False
End With

You can use .Color instead of .ColorIndex and you can also use RGB() to more easily set the value
so change your code to
.Interior.Color = RGB(&H9C,&H57,&H00)

Please, try the next code. Formatting the whole column will consume a lot of Excel resources, slows down the process of formulas update and it useless. The above code format only the B:B column having data:
Sub SetFormatRngMultiple_Cond()
Dim ws As Worksheet, lastR As Long, rngF As Range
Set ws = ActiveSheet
lastR = ws.Range("B" & ws.rows.count).End(xlUp).row
Set rngF = ws.Range("B2:B" & lastR)
With rngF
'first condition:
With .FormatConditions
.Delete
.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=2"
End With
With .FormatConditions(.FormatConditions.count)
.Font.Color = 1137094
.Interior.Color = vbYellow
.SetFirstPriority: .StopIfTrue = False
End With
'second condition:
With .FormatConditions
.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=1"
End With
With .FormatConditions(.FormatConditions.count)
.Font.Color = 5287936
.Interior.Color = 11854022
.StopIfTrue = False
End With
'third condition:
With .FormatConditions
.Add Type:=xlTextString, String:="OK", TextOperator:=xlContains
End With
With .FormatConditions(.FormatConditions.count)
.Font.Color = 5287936
.Interior.Color = 11854022
.StopIfTrue = False
End With
'fourth condition:
With .FormatConditions
.Add Type:=xlTextString, String:="kritish", TextOperator:=xlContains
End With
With .FormatConditions(.FormatConditions.count)
.Font.Color = vbRed
.Interior.Color = 14083324
.StopIfTrue = False
End With
End With
End Sub

Related

Is there a way to create a conditional formatting loop in VBA?

I have a large table spanning from D5 to AM39. Each column has its average value in cell D40, E40, F40, etc. I want to format the cells so that if the number in that column is higher than the average, color green and if lower color red.
I am extremely new to VBA but have this script thus far that is supposed to color cells greater than average but does not work (I think it has something to do with Cells(4,39) index being wrong, but am not sure.
Application.CutCopyMode = False
With Range(Cells(5, 39), Cells(4, 39))
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreater, _
Formula1:="=$D40"
.FormatConditions(1).Interior.color = RGB(0, 150, 0)
End With
End Sub
Appreciate any tips
EDIT********
Using the record macro feature I believe I have a closer solution to what I am looking for, however, the formatting doesn't align with the averages per row (cells are red that should be green, and vice versa)
With Range(Cells(39, 4), Cells(5, 39)).Select
Application.CutCopyMode = False
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreater, _
Formula1:="=D$40"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font
.color = -16752384
.TintAndShade = 0
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.color = 13561798
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Application.CutCopyMode = False
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlLess, _
Formula1:="=D$40"
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
End With
End Sub
Try this (using the built-in "compare to average" CF feature)
Sub AddCF()
Dim rngData As Range, col As Range
Set rngData = ActiveSheet.Range("D5:AM39") 'your table data
Application.ScreenUpdating = False
For Each col In rngData.Columns 'for each column in the data range
With col.FormatConditions.AddAboveAverage 'for >Avg
.AboveBelow = xlAboveAverage
.Interior.Color = vbRed
End With
With col.FormatConditions.AddAboveAverage 'for <Avg
.AboveBelow = xlBelowAverage
.Interior.Color = 5296274
End With
Next col
End Sub
If you want to use your existing average formulas:
Sub AddCF2()
Dim rngData As Range, col As Range, addr
Set rngData = ActiveSheet.Range("D5:AM39")
Application.ScreenUpdating = False
For Each col In rngData.Columns 'for each column in the data range
'absolute row, relative column address
addr = col.Cells(col.Cells.Count).Offset(1).Address(True, False) 'avg cell address
With col.FormatConditions
With .Add(Type:=xlCellValue, Operator:=xlGreater, Formula1:="=" & addr)
.Font.Color = -16383844
.Interior.Color = 13551615
End With
With .Add(Type:=xlCellValue, Operator:=xlLess, Formula1:="=" & addr)
.Font.Color = -16752384
.Interior.Color = 13561798
End With
End With
Next col
End Sub

VBA MACRO to color ONE cell right to the Selected cells

I have a macro that makes a formatting rule of multiple cell areas and must paint the cell yellow if it contains "S" and it works. But I would also like the cell to the right of the cell that contains "S" painted yellow, but only one cell to the right - not the whole row, is that possible? I imagine it's going to take place inside the "WITH statement, but I can not really move on
Sub Makro2()
Range("D6:E30,G6:H30,J6:K30,M6:N30,P6:Q30").Select
Range("P6").Activate
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, _
Formula1:="=""S"""
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
End Sub
I tried explaining in a comment the involvements of trying to conditional format of a discontinuous range. For the cell really processed by your shown code, you can accomplish what you need using the next code. The basis of conditional formatting behavior is that it formats only the cell where the conditional format belongs:
Sub Makro2Bis()
Dim rng As Range, offrng As Range
Set rng = Range("P6"): Set offrng = rng.Offset(0, 1)
With rng
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=""S"""
.FormatConditions(1).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
With offrng
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & rng.Address(0, 0) & "= ""S"""
.FormatConditions(1).Interior.Color = rng.FormatConditions(1).Interior.Color
.FormatConditions(1).StopIfTrue = False
End With
End Sub
Please, test it and send some feedback.
Edited:
Please, test the (more complicated) version creating the conditional formatting for the discontinue range, in a way you asked for: The right neighbour cell will have the interior yellow, too:
Sub Makro3Bis()
Dim rng As Range, arr, rng1 As Range, rng2 As Range, rng3 As Range
Set rng = Range("D6:E30,G6:H30,J6:K30,M6:N30,P6:Q30")
arr = buildThreeRngs(rng)
Set rng1 = arr(0) 'the first column of the discontinuous range areas
Set rng2 = arr(1) 'the second column of the discontinuous range areas
Set rng3 = arr(2) 'the next column after the discontinuous range areas
With rng1
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=""S"""
.FormatConditions(1).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
With rng2 'it will have two conditions. The second one relative to its left neighbour cell.
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=""S"""
.FormatConditions(1).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & rng1.cells(1).Address(0, 0) & "= ""S"""
.FormatConditions(2).Interior.Color = rng1.FormatConditions(1).Interior.Color
.FormatConditions(2).StopIfTrue = False
End With
With rng3
.FormatConditions.Delete
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & rng2.cells(1).Address(0, 0) & "= ""S"""
.FormatConditions(1).Interior.Color = rng.FormatConditions(1).Interior.Color
.FormatConditions(1).StopIfTrue = False
End With
End Sub
Please, test it and send some feedback.
Second Edit:
Looking only to your picture and not basing on the code you posted, probably, the my first code (for one cell) adapted in the next way should be what you need:
Sub Makro2BisBis()
Dim rng As Range, offrng As Range
Set rng = Range("D6:D30,G6:G30,J6:J30,M6:M30,P6:P30")
Set offrng = rng.Offset(0, 1)
Debug.Print offrng.Address: Stop
With rng
.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=""S"""
.FormatConditions(1).SetFirstPriority
With .FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.FormatConditions(1).StopIfTrue = False
End With
With offrng
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & rng.cells(1).Address(0, 0) & "= ""S"""
.FormatConditions(1).Interior.Color = rng.FormatConditions(1).Interior.Color
.FormatConditions(1).StopIfTrue = False
End With
End Sub
It will make yellow the cells in the range you have in your code, but using only each area first column...
Please, test it and send some feedback.
Conditional Formatting in VBA
For the second part in Excel, you would use the following Conditional Formatting formula:
=D6="s"
The Code
Option Explicit
Sub Makro2()
Const ColOffset As Long = 1
Const Criteria As String = "s"
Dim rg As Range: Set rg = Range("D6:D30,G6:G30,J6:J30,M6:M30,P6:P30")
' xlCellValue
With rg
.ClearFormats
.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, _
Formula1:="=""" & Criteria & """"
With .FormatConditions(.FormatConditions.Count)
.SetFirstPriority
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.StopIfTrue = False
End With
End With
' xlExpression
With rg.Offset(, ColOffset)
.ClearFormats
.FormatConditions.Add Type:=xlExpression, _
Formula1:="=" & .Cells(1).Offset(, -ColOffset).Address(0, 0) _
& "=""" & Criteria & """"
With .FormatConditions(.FormatConditions.Count)
.SetFirstPriority
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
.StopIfTrue = False
End With
End With
End Sub

Bold the entire row based on a cell's font

I have a set of data in columns A to Z, if any cells in Column F is bolded, shall call to bold the entire row.
For example, F3 and F80 is bolded. A3:Z3 and A80:Z80 shall be bolded. My code only works until bolding cells in column F, can't proceed to bold the entire row.
Sub Bold()
Dim CheckRange As Range
Dim cell As Range
With ActiveSheet
Set CheckRange = .Range("F2:F" & .Cells(.Rows.Count, "F").End(xlUp).Row)
End With
With CheckRange
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreaterEqual, formula1:="1000000"
With .FormatConditions(1)
.Font.Bold = True
.StopIfTrue = False
End With
For Each cell In CheckRange
If cell(cell.Row, 6).Font.Bold = True Then
cell.EntireRow.Font.Bold = True
End If
Next
End Sub
Any help is much appreciated.
May be using a formula for the conditional formatting is better
Sub Bold()
With ActiveSheet.UsedRange
.FormatConditions.Delete
.Range("A1:Z" & .Cells(Rows.Count, 6).End(xlUp).Row).FormatConditions.Add Type:=xlExpression, Formula1:="=$F1>=1000000"
With .FormatConditions(1)
.Font.Bold = True
.StopIfTrue = False
End With
End With
End Sub
Or to adhere to your code you can use offset and resize in the loop
Sub Bold()
Dim checkRange As Range, cell As Range
With ActiveSheet
Set checkRange = .Range("F2:F" & .Cells(.Rows.Count, "F").End(xlUp).Row)
End With
With checkRange
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreaterEqual, Formula1:="1000000"
With .FormatConditions(1)
.Font.Bold = True
.StopIfTrue = False
End With
End With
For Each cell In checkRange
If cell.DisplayFormat.Font.Bold = True Then
cell.Offset(, -5).Resize(1, 26).Font.Bold = True
End If
Next cell
End Sub
The code sample is missing an end with after the first one to run.
Other than that, the issue is here: If cell(cell.Row, 6).Font.Bold
cell is already a Range type reference to the cell you need, so you don't need to look up anything, in fact doing that causes it to point elsewhere with the cell function: for example this is from the watch window, note the value difference:
Watch : : cell.Address : "$F$2" : String : Module1.Bold
Watch : : cell(cell.Row, 6).Address : "$K$3" : Variant/String : Module1.Bold
This is the full code:
Sub Bold()
Dim CheckRange As Range
Dim cell As Range
With ActiveSheet
Set CheckRange = .Range("F2:F" & .Cells(.Rows.Count, "F").End(xlUp).Row)
End With
With CheckRange
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreaterEqual, Formula1:="1000000"
With .FormatConditions(1)
.Font.Bold = True
.StopIfTrue = False
End With
End With
For Each cell In CheckRange
If cell.Font.Bold = True Then
cell.EntireRow.Font.Bold = True
End If
Next
End Sub

Format Conditions based on value length

How can I use VBA to Format a cell if it contains some value with a length greater than 1?
(This rule should ofc apply to all cells in the range)
Set text_value = Range("$A:$A").FormatConditions.Add(Type:=xlCellValue, Operator:=xlEqual, Formula1:="=--LEN($A1)>1")
With text_value
.Interior.Color = vbRed
.Borders.LineStyle = xlContinuous
End With
This is what I have tried, but does not work!
Change Type to xlExpression, because you are using formula as a criteria and it will work.
Set text_value = Range("$A:$A").FormatConditions.Add(Type:=xlExpression, Operator:=xlEqual, Formula1:="=LEN($A1)>1")
With text_value
.Interior.Color = vbRed
.Borders.LineStyle = xlContinuous
End With

Find/replace limited to one column but many worksheets

I'll start by saying the only VBA I know is trial and error from manipulating recorded macros. I am a CPA trying to learn VBA the hard way (and wishing I had gone to school for computer programming instead!).
I have large workbooks with multiple worksheets. Cells highlighted yellow in column G need to be formatted in a specific way in order for the file to import correctly to a web-based program. They need to remain highlighted yellow, be right/bottom aligned, and custom format of mm/dd/yyyy. I recorded a macro doing find/replace to try to replace all yellow highlighted cells within column G with highlighted yellow, bottom/right justified, custom format mm/dd/yyyy, but it's not limiting the replace to only column G. I also have no clue how to get the macro to loop through all the worksheets before finishing. Help?!
This is what I have from my basic macro recording:
Sub Macro2()
'
' Macro2 Macro
'
'
Columns("G:G").Select
Range("G:G").Activate
With Application.FindFormat.Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Application.ReplaceFormat.Clear
Application.ReplaceFormat.NumberFormat = "mm/dd/yyyy"
With Application.ReplaceFormat
.HorizontalAlignment = xlRight
.VerticalAlignment = xlBottom
End With
With Application.ReplaceFormat.Font
.Subscript = False
.TintAndShade = 0
End With
With Application.ReplaceFormat.Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Cells.Replace What:="", Replacement:="", LookAt:=xlPart, SearchOrder:= _
xlByRows, MatchCase:=False, SearchFormat:=True, ReplaceFormat:=True
End Sub
EDITED POST TO ADD: Please see screenshot of a typical sheet I am trying to reformat. Again, I only need to worry about changing the formatting on cells that are yellow highlighted, but I'm still having trouble limiting the find/replace to column G only... [1]: [https://i.stack.imgur.com/wRu30.jpg]
Here's some code that seems to do what you describe. I've placed a lot of .select statements in the code so that you can learn how it works by stepping through it, but you should remove all those once you understand. Also, I have some commented out code at the bottom which you can use to loop through multiple sheets. The animated gif shows the code running on an example I made up. Let me know if you have questions.
Sub reformat()
Dim sh As Worksheet, r As Range, cell As Range
Set sh = ActiveSheet
Set r = sh.Range("G1")
r.Select
If r.Offset(1, 0) <> "" Then Set r = sh.Range(r, r.End(xlDown))
r.Select
For Each cell In r
With cell
.Select
If .Interior.Color = 65535 Then
.HorizontalAlignment = xlRight
.VerticalAlignment = xlBottom
.NumberFormat = "mm/dd/yyyy"
End If
End With
Next
For Each sh In ThisWorkbook.Worksheets
'place the above code in this loop if you want
'to apply the above to all worksheets in the workbook
'also remove the set sh=ActiveSheet line
Next sh
End Sub
If you are trying to make sense of recorded code, the first thing to do is get rid of all the extraneous, verbose code that was added but doesn't do anything. Recorded code covers all aspects of an operation whether you require them or not.
This is a rewrite of your original using only what is required.
Sub yellowSpecialReplace()
Dim w As Long
Application.DisplayAlerts = False
With Application.FindFormat
.Clear
.Interior.Color = 65535
End With
With Application.ReplaceFormat
.Clear
.NumberFormat = "mm/dd/yyyy"
.HorizontalAlignment = xlRight
.VerticalAlignment = xlBottom
End With
With ActiveWorkbook
For w = 1 To .Worksheets.Count
With Worksheets(w).Columns("G:G")
.Cells.Replace What:=vbNullString, Replacement:=vbNullString, _
LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchFormat:=True, ReplaceFormat:=True
End With
Next w
End With
Application.DisplayAlerts = True
End Sub
Cycle through each worksheet in the active workbook then AutoFilter on the cell color then apply the changes to the visible cells..
sub yellowSpecial()
dim w as long
with activeworkbook
for w=1 to .worksheets.count
with worksheets(w)
if .autofiltermode then .autofiltermode = false
with .range(.cells(1, "G"), .cells(.rows.count, "G").end(xlup))
.autofilter field:=1, criteria1:=vbyellow, operator:=xlFilterCellColor
with .resize(.rows.count-1, .columns.count).offset(1,0)
if cbool(application.subtotal(103,.cells)) then
with .specialcells(xlcelltypevisible)
.HorizontalAlignment = xlRight
.VerticalAlignment = xlBottom
.numberformat = "mm/dd/yyyy"
end with
end if
end with
end with
if .autofiltermode then .autofiltermode = false
end with
next w
end with
end sub

Resources