1

i 've been trying to make a macro to highlight dates with their entire rows if they fell into a specific date interval. The problem i have encoutered is : when macro finds a certain date it colours the entire row of that date and then should go onto the next .find with .findnext. However the macro gets stuck in a loop in here

Do While Not c Is Nothing
     c.EntireRow.Interior.Color = vbCyan
     Set c = Dates.FindNext
Loop

with c value as 2021.03.01 (as StartDate) My code looks like this:

        Private Sub CommandButton2_Click()
Dim c As Range
Dim first As String
Dim last As String
Dim StartDate As Date
Dim EndDate As Date
Dim DateLooper As Date

    first = CLng(Range("E2").Value)
    last = CLng(Range("G2").Value)

For Each Cell In ActiveSheet.Range("H2:H" & Cells(Rows.Count, 8).End(xlUp).Row)
  Sheet = Cell
  StartDate = first
  EndDate = last

  For DateLooper = StartDate To EndDate
    Set Dates = Worksheets(Sheet).Range("P:P")
    Set c = Dates.Find(What:=DateLooper)

        Do While Not c Is Nothing
        c.EntireRow.Interior.Color = vbCyan
        Set c = Dates.FindNext(c)
        Loop

  Next DateLooper
Set c = Nothing
Next Cell
End Sub

What's the problem here? Thank you for your time and help. Maybe it's because of the c being a date?

VBasic2008
  • 44,888
  • 5
  • 17
  • 28
baxius
  • 37
  • 8
  • 1
    Dates can be tricky, but your `Do` loop will never end if c is not nothing. The usual way to exit is to store the address of the first found cell and then loop until you get back to that address meaning that you are back to where you started. – SJR Mar 17 '21 at 12:30
  • Is the H:H column sorted? – FaneDuru Mar 17 '21 at 12:32
  • How many rows are in H:H column? I mean an approximation... – FaneDuru Mar 17 '21 at 12:59

3 Answers3

2

iadd fAddress variable and condition to loop

Private Sub CommandButton2_Click()
Dim c As Range
Dim first As String
Dim last As String
Dim StartDate As Date
Dim EndDate As Date
Dim DateLooper As Date
dim fAddress as String
    first = CLng(Range("E2").Value)
    last = CLng(Range("G2").Value)

For Each Cell In ActiveSheet.Range("H2:H" & Cells(Rows.Count, 8).End(xlUp).Row)
  Sheet = Cell
  StartDate = first
  EndDate = last

  For DateLooper = StartDate To EndDate
    Set Dates = Worksheets(Sheet).Range("P:P")
    Set c = Dates.Find(What:=DateLooper)
    if not c is nothing then 
        fAddress  = c.address
        Do 
           c.EntireRow.Interior.Color = vbCyan
           Set c = Dates.FindNext(c)
        Loop While Not c Is Nothing and fAddress  <> c.address
    end if
  Next DateLooper
Set c = Nothing
Next Cell
End Sub
Tomasz
  • 426
  • 2
  • 10
  • true should be string type variable comparing or without address prop. – Tomasz Mar 17 '21 at 12:39
  • 2
    With `If Not c Is Nothing Then` you have determined that `c` is 'something' (a cell range). Therefore in the `Do...Loop` it can never ever be nothing because the `FindNext` will always find 'something', even if it is all the time the same 'something'. Only by checking the address, you are avoiding the endless loop, hence in `Loop While...` the part `Not c Is Nothing And` is redundant. – VBasic2008 Mar 17 '21 at 14:00
  • yes i just focus to add necesary parts of code. not even test it :) – Tomasz Mar 17 '21 at 16:34
2

Try the next way, please. Not tested, but it should be fast enough. It iterates between an array elements and put the range to be colored in a Union range, to be colored at once, at the end:

Private Sub CommandButton2_Click()
 Dim StartDate As Date, rngCol As Range, EndDate As Date
 Dim firstRow As Long, arrD, i As Long, rngH As Range

 Set rngH = Range("H2:H" & cells(rows.count, 8).End(xlUp).row)
 arrD = rngH.value
 StartDate = Range("E2").value
 EndDate = Range("G2").value
 firstRow = rngH.Find(what:=Date, LookIn:=xlValues, lookat:=xlWhole).row - 1lookat:=xlWhole).row - 1
  For i = firstRow To UBound(arrD)
    If CDate(arrD(i, 1)) = EndDate Then Exit For
    If CDate(arrD(i, 1)) = StartDate Then
        If rngCol Is Nothing Then
            Set rngCol = cells(i + 1, 1)
        Else
            Set rngCol = Union(rngCol, cells(i + 1, 1))
        End If
    End If
  Next i
  If Not rngCol Is Nothing Then rngCol.EntireRow.Interior.Color = vbCyan
End Sub

It assumes that the H:H column is sorted ascendant.

FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • Thank you for your time and help, but i've started to analyze another code by VBasic2008 as it is my codes modified version. – baxius Mar 18 '21 at 10:57
  • @baxius: I only tried to supply the fastest way. If not convenient for you, I do not have a problem. – FaneDuru Mar 18 '21 at 11:18
2

Highlight Entire Rows of Cells With Criteria

  • Writes the start and end dates to variables (E2, G2).
  • Loops through a column (H) range containing worksheet names.
  • In each of those worksheets (dws), loops through the dates (DateLooper), and attempts to find the date in cells (dCell) of the date column (P).
  • If found, highlights the cell's entire row.

The Code

Option Explicit

Private Sub CommandButton2_Click()
    
    Dim ws As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    Dim sws As Worksheet: Set sws = ActiveSheet
    Dim StartDate As Date: StartDate = sws.Range("E2").Value
    Dim EndDate As Date: EndDate = sws.Range("G2").Value
    Dim wrg As Range
    Set wrg = sws.Range("H2", sws.Cells(sws.Rows.Count, "H").End(xlUp))
    
    Dim dws As Worksheet
    Dim drg As Range
    Dim dCell As Range
    Dim wCell As Range
    Dim DateLooper As Date
    Dim fAddr As String
    
    For Each wCell In wrg.Cells ' loop through list of worksheet names
        Set dws = wb.Worksheets(wCell.Value)
        Set drg = dws.Range("P2", dws.Cells(dws.Rows.Count, "P").End(xlUp))
        For DateLooper = StartDate To EndDate ' loop through dates
            Set dCell = drg.Find(What:=DateLooper) ' find dates
            If Not dCell Is Nothing Then
                fAddr = dCell.Address
                Do
                    dCell.EntireRow.Interior.Color = vbCyan
                    Set dCell = drg.FindNext(dCell)
                Loop Until dCell.Address = fAddr
            End If
            Set dCell = Nothing
        Next DateLooper
    Next wCell

End Sub
VBasic2008
  • 44,888
  • 5
  • 17
  • 28
  • Hello, i have tried your code and everything works fine until one moment. If a cell with desired date is merged with another cell (1 date in 2 cells) the ,,Loop until dCel.Adress = fAddr returns an error as the previous line sets dCell as nothing and in accordingly the Adress returns varbiable or object not set. Another ,, is nothing" handler is needed before ,,Loop until,, ?? – baxius Mar 18 '21 at 10:55
  • 1
    You didn't mention any merged cells. What would you like to happen when the code encounters a merged cell? – VBasic2008 Mar 18 '21 at 10:59
  • Yeah, these merged cells are a rare occasion, but they still exist. I would like that the code would highlight the whole row of the merged cell. – baxius Mar 18 '21 at 11:52
  • Maybe with ,,MergeArea.Rows.Count,, ? – baxius Mar 18 '21 at 11:57