Finding Last Row With Data With Formatted Cells Below - excel

I need to identify, (by highlighting), when there is data missing from a certain column. In other words, I have a column of data specifying a country. Above this column there are blanks and below this column there are blanks. The topmost row of the data stays the same (the data always starts at row 4), but the bottom is variable. Also, due to the way this data is output, there seems to be 3 or so rows of blank but formatted cells at the bottom of the table which excel recognizes as 'used'. Here is my code thus far:
With ThisWorkbook.ActiveSheet
LastRowCountry = .Range("H" & .Rows.Count).End(xlUp).Row
End With
The Piece of code that is specific to my goal is:
'Search for blank Geo tags
With ThisWorkbook.ActiveSheet
If IsEmpty(Cells(LastRowCountry, "H")) = True Then
'Highlight Columns
With Range(Cells(4, "H"), Cells(LastRow, "H")).Interior
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent2
.TintAndShade = 0.799981688894314
.PatternTintAndShade = 0
End With
End If
End With
In this form it fails to recognize any blanks in the column and never highlights. Before this I preceded the code with:
With ActiveSheet.Cells.SpecialCells(xlLastCell)
LastRow = .Row
LastCol = .Column
End With
which always highlighted the column (I assume because it was detecting the blank but formatted cells hanging off the bottom of the table. Thanks in advance to anyone who takes this on.
Steve

I have tried this here and it works
Sub CheckForEmptyCells(Byref sh as Worksheet, ByRef col as string)
Dim lastR&
lastR = sh.Range(col & Rows.Count).End(xlUp).Row
Dim r As Range: Set r = Range(col & "5:" & col & lastR)
If Not r.Find("") Is Nothing Then
With r.Interior
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent2
.TintAndShade = 0.799981688894314
.PatternTintAndShade = 0
End With
End If
End Sub
Note: this routine checks only if the given column has empty cells in between its own first and last cells. If the goal is to check the whole column (last cell of the column might itself be empty), then you should use instead: lastR = sh.UsedRange.Rows.Count

Related

VBA Compare single row values and highlight the entire row if different

My code uses conditional formatting to look at the row values in Column A "Order ID", compares them, and then formats the cell if the row values are different. Instead of formatting the cell, how do I format the entire row based off of consecutive row values in Column A "Order ID" being different?
Said differently - if the value in Column A "Order ID" is different from the previous value in Column A "Order ID", I want to format the entire row that is different. My data is variable everyday so I need to use VBA!
Here is the output of my current code:
This is the desired outcome:
Here is the code
Sub Fulfillment()
'
' Fulfillment Macro
' Format the order number in column A as plum
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=MOD(SUM((A$2:A2<>A$1:A1)*1),2)=0"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font.Color = RGB(0, 0, 0)
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = RGB(221, 160, 221)
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Thank you! I do not necessarily need a conditional formatting solution, just a VBA solution that works dynamically.
A Different Flavor of Banded Rows
Option Explicit
Sub Fulfillment()
'
' Fulfillment Macro
' Format the order number in column A as plum
Const CriteriaColumn As Long = 1
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1") ' adjust
Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion
Set rg = rg.Resize(rg.Rows.Count - 2).Offset(2) ' exclude first two rows
Application.ScreenUpdating = False
rg.Interior.Color = xlNone
Dim Col As Long: Col = 1
Dim cell As Range
Dim r As Long
For Each cell In rg.Columns(CriteriaColumn).Cells
r = r + 1
If cell.Value <> cell.Offset(-1).Value Then Col = Col Mod 2 + 1
If Col = 2 Then rg.Rows(r).Interior.Color = RGB(221, 160, 221)
Next cell
Application.ScreenUpdating = True
MsgBox "Fulfillment accomplished.", vbInformation
End Sub

How to add a bottom border along row that has merged cells with VBA formatConditons

I have a sheet where in column B the cells are merged with the row below. In the rest of the columns the rows are not merged.
I want to add a VBA code that draws a line across the bottom of the entire row along the bottom of the merged cells. It's as if I wanted to draw a bottom border every other row for all columns (except B where each merged cell would have the bottom border). I have tried using the following code but the border is not drawn under the merged cells
Sub FormatTest()
With Sheets("Test")
With .Range("$B:$Z")
.FormatConditions.Add xlExpression, Formula1:="=mod(row(),2)=0"
With .FormatConditions(1).Borders(xlBottom)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlThin
End With
.FormatConditions(1).StopIfTrue = False
End With
End With
End Sub
Here is an example of what i want to achieve
I want to achieve this with conditional formatting because the number of rows will change from time to time and i don't want to have borders on empty cells.
The photo is just an example because there are many rows and on different sheets I will have a different number of columns so I just want to apply it to the whole row... Can anyone help?
You can try using something along these lines:
(Just might need to tinker with the row = 1 to get the correct starting position)
Dim row As Long
Dim lastRow As Long
Dim lCol As Long
Dim letter As String
With ThisWorkbook.Worksheets("your sheet name")
' clear previous borders
.Range("A5:ZZ30000").Borders.Linestyle = xlNone
' add new borders
lastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
lCol = .Cells(1, .Columns.Count).End(xlToLeft).Column ' checks row 1 for last col
letter = Split(.Cells(1, lCol).Address, "$")(1)
For row = 1 To lastRow+1 Step 2
With .Range("B" & row & letter & row).Borders(xlBottom)
.LineStyle = xlContinuous
.Weight = xlThin
End With
Next
End With

Highlight cell if greater than today

I'm trying to highlight cells that have a date greater than today's date.
Column H is formatted as Date.
I have the following:
Sub Test()
Dim lrow As Long
lrow = Cells(Rows.Count, 1).End(xlUp).Row
Columns("H:H").EntireColumn.AutoFit
If Range("H2:H" & lrow).Value > Date Then Cell.Interior.Color = vbYellow
End Sub
I get a "Type Mismatch" error.
Range("H2:H" & lrow).Value will be a 2D array (the Value of a Range is always a 2D array if more than a single cell is involved); you're getting a type mismatch error because you can't compare a 2D array to a Date; if you can't use a conditional formatting, you need to compare the individual array subscripts.
Last thing you want to do is to iterate each individual cells (otherwise your next question will be "how do I make this loop run faster?"). Get that array into a Variant, and iterate that array - since it's only 1 column, make it a 1D array with Application.Transpose:
Dim values As Variant
values = Application.Transpose(Range("H2:H" & lastRow).Value)
Dim i As Long, current As Long
For i = LBound(values) To UBound(values)
current = i + 1 'array would be 1-based, so to start at row 2 we need to offset by 1
If values(i) > Date Then
ActiveSheet.Cells(current, 8).Interior.Color = vbYellow
End If
Next
That way you only hit the worksheet when you have to.
In response to #MatthieuGuindon's suggestion to #CharlesPL's answer, here's some code that does the conditional formatting. I've set it so it highlights dates that are after the day you run it as a bright yellow.
Option Explicit
Sub setCondFormat()
Dim lrow As Long
lrow = ActiveSheet.Range("H" & ActiveSheet.Rows.Count).End(xlUp).Row
With Range("H2:H" & lrow)
.FormatConditions.Delete
.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=H2>TODAY()"
With .FormatConditions(.FormatConditions.Count)
.SetFirstPriority
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
End With
End With
End With
End Sub
Use conditional formatting! As the name suggests, this is build for that!
Microsoft blog post on date conditional formating
I would recommend iterating over the range of cells and testing each cell individually. Please see below.
Dim rng As Range, cell As Range
Set rng = Range("H:H")
For Each cell In rng
If cell.Value > Date Then cell.Interior.Color = vbYellow
Next cell

VBA StrComp - Compare values with exceptions

enter image description hereI have today's data in column D which I want to compare with yesterday's data in column F, row wise.
Below is the code I'm using to compare and highlight duplicates.
A) Highlighting blank cells which I don't want.
B) I want to handle some exceptions like I don't wish to highlight $0.00 or specific text "No Data"
Sub CompareAndHighlight()
Dim Myrng1 As Range, Myrng2 As Range, i As Long, j As Long
Application.ScreenUpdating = False
For i = 3 To Sheets("Sheet1").Range("D" & Rows.Count).End(xlUp).Row
Set Myrng1 = Sheets("Sheet1").Range("D" & i)
For j = 3 To Sheets("Sheet1").Range("F" & Rows.Count).End(xlUp).Row
Set Myrng2 = Sheets("Sheet1").Range("F" & j)
If StrComp(Trim(Myrng1.Text), Trim(Myrng2.Text), vbTextCompare) = 0 Then
'If Myrng1.Value = Myrng2.Value Then
Myrng1.Interior.Color = RGB(255, 255, 0)
End If
Set Myrng2 = Nothing
Next j
Set Myrng1 = Nothing
Next i
Application.ScreenUpdating = True
End Sub
Data giving random errors on running macros multiple times after clearing highlighted colors.
Use the conditional formatting function.
Columns("A:A").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
Then after this create one loop that goes through your range and turns the colour of the cell to no colour where your conditions are met, alternatively you could just filter the data to exclude your cases, such as "No Data", and copy and paste the results into a new column. In fact you do not really need vba for this.
sticking with VBA you could try the following code:
Option Explicit
Sub CompareAndHighlight()
Dim refRng As Range, cell As Range
Application.ScreenUpdating = False
With Worksheets("Sheet1")
Set refRng = .Range("F3", .Cells(.Rows.Count, "F").End(xlUp)).SpecialCells(XlCellType.xlCellTypeConstants)
For Each cell In .Range("D3", .Cells(.Rows.Count, "D").End(xlUp)).SpecialCells(XlCellType.xlCellTypeConstants)
If cell.value <> 0 And cell.value <> "No Data" Then
If refRng.Find(what:=cell.value, LookIn:=xlFormulas, lookat:=xlWhole, MatchCase:=False) Is Nothing Then cell.Interior.color = RGB(255, 255, 0)
End If
Next cell
End With
Application.ScreenUpdating = True
End Sub

Color formatting of Rows based on input values for a cell

There is some data in the worksheet, which includes a column for time. Time Range is provided as an Input to format the color of the time cells within that time range. Color formatting of the rows containing those cells is also desired but is not observed in the output. It is to mention that the start time or end time provided as input is sometimes not matching value of any time cell.
Attached is the code and is not giving desired output.
Any kind of help will be appreciated.
Dim ws As Worksheet
Dim timeRange As Range
Set ws = Sheets("Worksheet") 'Name of my worksheet goes here.
Set timeRange = ws.Range("D:D")
'input the lower limit and the upper limit of the search range
Dim Start_Time As Variant
Dim End_Time As Variant
Start_Time = InputBox(prompt:="Enter the Start_Time(hh:mm:ss.000)")
End_Time = InputBox(prompt:="Enter the End_Time(hh:mm:ss.000)")
timeRange.FormatConditions.Add Type:=xlCellValue, Operator:=xlBetween, _
Formula1:=Start_Time, Formula2:=End_Time
timeRange.FormatConditions(timeRange.FormatConditions.Count).SetFirstPriority
With timeRange.FormatConditions(1).Font
.Color = -16383844
.TintAndShade = 0
End With
With timeRange.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13551615
.TintAndShade = 0
End With
timeRange.FormatConditions(1).StopIfTrue = False
'Loop to format the rows that contains those time values
Dim Range_Search As String
For Each c In Range("D:D")
If c.Interior.Color = 13551615 Then
Range_Search = "A" & c.Row & ":" & "H" & c.Row
ws.Range(Range_Search).Interior.Color = 13551615
End If
Next c
The final loop in your code won't work. You need to change it to:
For Each c In Range("D:D")
If c.Interior.Color = 13551615 Then
Range_Search = "A" & c.Row & ":" & "H" & c.Row
Range(Range_Search).Select
Selection.Interior.Color = 13551615
End If
Next c
I'm not sure what the "Let" is supposed to do in your statement, but it's not necessary. Also, you need to get the Row from cell c, not just c.
To make this even better, I would reference the cells by the worksheet as this will prevent possible problems from selecting different worksheets:
Dim ws As worksheet
Dim timeRange As Range
Set ws = Sheets("mySheet") 'Obviously change this to your sheet name
Set timeRange = ws.Range("D:D")
Then replace "Selection." with "timeRange." in your code, so
Selection.FormatConditions.Add Type:=xlCellValue, Operator:=xlBetween, _
Formula1:=Start_Time, Formula2:=End_Time
becomes:
timeRange.FormatConditions.Add Type:=xlCellValue, Operator:=xlBetween, _
Formula1:=Start_Time, Formula2:=End_Time
Then change your final loop to do something similar:
For Each c In timeRange
If c.Interior.Color = 13551615 Then
ws.Range("A" & c.Row & ":" & "H" & c.Row).Interior.Color = 13551615
End If
Next c
Selecting cells is not efficient and can cause problems if something else inadvertently gets selected while you are trying to run the code.
I figured it out. Thanks to OpiesDad for help.
Basically the format condition color is not recognize by the vba until you add DisplayFormat. before the interior.color command. so something like.
For Each c In timeRange
If c.**DisplayFormat**.Interior.Color = 13551615 Then
ws.Range("A" & c.Row & ":" & "H" & c.Row).Interior.Color = 13551615
End If
Next c

Resources