I've been trying to add the entire row that meets the highlight criteria to an array but I've been struggling getting it to work.
The code loops through multiple identifiers and highlight them in red based off of the preconditions. I would like to add the entire row to an array for all rows meeting the precondition criteria.
Sub SWAPS101()
'red color
' If "Security Type" = SW
' If "New Position Ind" = N
' If "Prior Price" = 100
' If "Current Price" does not equal 100
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Object
'Sheets("Output").Activate
With ActiveSheet
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("E2:E" & LastRow) 'new position
If cell = "N" And cell.Offset(, 16) = "SW" And cell.Offset(, 5) = 100 _
And cell.Offset(, 4) <> 100 Then
With cell.EntireRow.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 6382079
.TintAndShade = 0
.PatternTintAndShade = 0
End With
' LastRow = Range("b65000").End(xlUp).Row
' For r = 2 To LastRow
Row = Row + 1
TempArray(Row, 1) = Cells(r, cell))
Next r
End If
Next cell
End With
End Sub
Using the Range.CurrentRegion property to isolate the 'island' of data radiating out from A1 is an easy method to restrict the 'scope' of the operation. You do not want to be copying thousands of blank cells into an array.
Sub SWAPS101()
'red color
' If "Security Type" = SW
' If "New Position Ind" = N
' If "Prior Price" = 100
' If "Current Price" does not equal 100
Dim a As Long, r As Long, c As Long, vVALs As Variant
With Sheets("Output")
'reset the environment
If .AutoFilterMode Then .AutoFilterMode = False
.Columns(5).Interior.Pattern = xlNone
With .Cells(1, 1).CurrentRegion
ReDim vVALs(1 To .Columns.Count, 1 To 1)
.AutoFilter field:=Application.Match("security type", .Rows(1), 0), Criteria1:="SW"
.AutoFilter field:=Application.Match("new position ind", .Rows(1), 0), Criteria1:="N"
.AutoFilter field:=Application.Match("prior price", .Rows(1), 0), Criteria1:=100
.AutoFilter field:=Application.Match("current price", .Rows(1), 0), Criteria1:="<>" & 100
With .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0)
'check to ensure that there is something to work with
If CBool(Application.Subtotal(103, .Cells)) Then
With Intersect(.Columns(5), .SpecialCells(xlCellTypeVisible))
.Cells.Interior.Color = vbRed
End With
Debug.Print .SpecialCells(xlCellTypeVisible).Areas.Count
With .SpecialCells(xlCellTypeVisible)
For a = 1 To .Areas.Count
Debug.Print .Areas(a).Rows.Count
For r = 1 To .Areas(a).Rows.Count
Debug.Print .Areas(a).Rows(r).Address(0, 0)
ReDim Preserve vVALs(1 To UBound(vVALs, 1), 1 To UBound(vVALs, 2) + 1)
For c = 1 To .Columns.Count
vVALs(c, UBound(vVALs, 2)) = _
.Areas(a).Rows(r).Cells(1, c).Value
Next c
Next r
Next a
vVALs = Application.Transpose(vVALs)
End With
'array is populated - do something with it
Debug.Print LBound(vVALs, 1) & ":" & UBound(vVALs, 1)
Debug.Print LBound(vVALs, 2) & ":" & UBound(vVALs, 2)
'this dumps the values starting a couple of rows down
With .Cells(.Rows.Count, 1).Offset(3, 0)
.Resize(UBound(vVALs, 1), UBound(vVALs, 2)) = vVALs
End With
End If
End With
End With
If .AutoFilterMode Then .AutoFilterMode = False
End With
End Sub
I've left a lot of the debug.print statements in so you can watch how the process loops through the rows of each Range.Areas property within the Range.SpecialCells method's xlCellTypeVisible set. Use F8 to step through the code while keeping an eye on the VBE's Immediate window ([Ctrl]+G).
Post-processing results
You can add ranges to an array, such as:
Dim myArray() As Variant 'declare an unallocated array.
myArray = Range("E2:E" & LastRow) 'myArray is now an allocated array, range being your row
My idea is to create union range uRng but I couldn't fill it in array so create temp sheet and past this range in it then fill the selection (the copied range) in array then delete this temp sheet.
this will work but I don't know if it is good way so this is just an idea because Jeeped answer seems the full answer for this question
Sub SWAPS101()
'red color
' If "Security Type" = SW
' If "New Position Ind" = N
' If "Prior Price" = 100
' If "Current Price" does not equal 100
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Range
Dim TempArray As Variant, uRng As Range, tempSH As Worksheet
'Sheets("Output").Activate
With ActiveSheet
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("E2:E" & LastRow) 'new position
If cell = "N" And cell.Offset(, 16) = "SW" And cell.Offset(, 5) = 100 _
And cell.Offset(, 4) <> 100 Then
With cell.EntireRow.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 6382079
.TintAndShade = 0
.PatternTintAndShade = 0
End With
If uRng Is Nothing Then
Set uRng = cell.EntireRow
Else
Set uRng = Union(uRng, cell.EntireRow)
End If
End If
Next cell
End With
If Not uRng Is Nothing Then
Application.ScreenUpdating = False
Set tempSH = Sheets.Add
uRng.Copy
tempSH.Paste
TempArray = Selection.Value
Application.DisplayAlerts = False
tempSH.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End If
End Sub
Related
I want to filter all the values except value in Array i.e. "B400", "A200", "C300".
I tried following code, none of the code is working
Dim rDataRange as Range
set rDataRange = Range("A1:P1000")
rDataRange.AutoFilter Field:=11, Criteria1:="<>" & Array("B400", "A200", "C300"), Operator:=xlFilterValues
rDataRange.AutoFilter Field:=11, Criteria1:=Array("<>B400", "<>A200", "<>C300"), Operator:=xlFilterValues
Please help me
Modified for your situation:
Option Explicit
Sub AutoFilterWorkaround()
Dim sht As Worksheet
Dim filterarr As Variant, tofindarr As Variant
Dim lastrow As Long, i As Long, j As Long, k As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
lastrow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
'List the parts of the words you need to find here
tofindarr = Array("B400", "A200", "C300")
ReDim filterarr(0 To 0)
j = 0
For i = 2 To lastrow
If sht.Cells(i, 11).Value <> tofindarr(0) And _
sht.Cells(i, 11).Value <> tofindarr(1) And _
sht.Cells(i, 11).Value <> tofindarr(2) Then
filterarr(j) = sht.Cells(i, 11).Value
j = j + 1
ReDim Preserve filterarr(0 To j)
End If
Next i
'Filter on array
sht.Range("$A$1:$P$" & lastrow).AutoFilter Field:=11, Criteria1:=Array(filterarr), Operator:=xlFilterValues
End Sub
There is an easier way to accomplish this then using a filter.
Dim lRow As Long
With ThisWorkbook.Sheets(1)
lRow = .Range("K" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
If .Cells(i, 11).Value = "A200" Or .Cells(i, 11).Value = "B400" Or .Cells(i, 11).Value = "C300" Then
.Cells(i, 11).EntireRow.Hidden = True
End If
Next i
End With
you could still use AutoFilter() in a sort of reverse mode:
Dim myRng As Range ' helper range variable
With Range("A1:P1000") ' reference wanted range to filter, header row included
.AutoFilter field:=11, Criteria1:=Array("B400", "A200", "C300"), Operator:=xlFilterValues ' filter on "not wanted" values
If Application.Subtotal(103, .Resize(, 1)) > 1 Then ' if any filtered cell other than header row
Set myRng = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' temporarily set 'myRng' to referenced range "not wanted" rows
.Parent.AutoFilterMode = False ' remove filters and show all rows
myRng.EntireRow.Hidden = True ' hide referenced range "not wanted" rows, leaving "wanted" rows only visible
With .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' reference referenced range "wanted" rows
.Select
' do what you want with "wanted" rows
End With
.EntireRow.Hidden = False ' unhide all referenced range rows
Else
.Parent.AutoFilterMode = False ' remove filters
End If
End With
I'd like to know if there's a way to do the following thing using VBA:
If the macro finds the word "Total" in the column B, then interior.color of the line where total is would be colored in Blue, and do it for all the "Total" words in the column B.
Note: I have different Totals... it's not only the word "Total"
LIKE THIS (i.e coloring from col A to F)
I tried with this but it's not working properly and the code is bad...
Sub forme_couleur()
Dim myRow As Integer
myRow = 1
While Not IsEmpty(Cells(myRow, 2))
If Cells(myRow, 2).Find(What:="Total") Is Nothing Then
myRow = myRow + 1
Else
Cells(myRow, 2).Find(What:="Total").Interior.Color = RGB(174, 240, 194)
End If
myRow = myRow + 1
Wend
End Sub
Consider:
Sub ColorMeBlue()
Dim i As Long, N As Long, s As String
N = Cells(Rows.Count, "B").End(xlUp).Row
s = "Total"
For i = 1 To N
If InStr(1, Cells(i, 2).Value, s) > 0 Then
Range("A" & i & ":F" & i).Interior.Color = RGB(174, 240, 194)
End If
Next i
End Sub
EDIT#1:
To refer to a range using columns by number, use:
Sub ColorMeBlue2()
Dim i As Long, N As Long, s As String
N = Cells(Rows.Count, "B").End(xlUp).Row
s = "Total"
Firstcol = 1
LastCol = 6
For i = 1 To N
If InStr(1, Cells(i, 2).Value, s) > 0 Then
Range(Cells(i, Firstcol), Cells(i, LastCol)).Interior.Color = RGB(174, 240, 194)
End If
Next i
End Sub
You can achieve this with conditional formatting, but if you must do it with VBA use something like the following:
Sub test()
For i = 1 To Cells(ActiveSheet.Rows.Count, "B").End(xlUp).Row
If InStr(1, Cells(i, 2), "Total") Then
With Cells(i, 2).EntireRow.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorLight2
.TintAndShade = 0.399975585192419
.PatternTintAndShade = 0
End With
End If
Next i
End Sub
Another Concept: You can go with the AutoFilter method. Using this method doesn't require any For loops, or any Ifs, just use all the cells that passes the AutoFilter criteria of ="*Total*" inside your Range.
Sub ColorMeBlue_Filter()
Dim i As Long, N As Long, s As String
Dim FirstCol As Long, LastCol As Long
Dim FiltRng As Range
N = Cells(Rows.Count, "B").End(xlUp).Row
s = "Total"
' (just for my testing)
'FirstCol = 1
'LastCol = 6
Range("A1").AutoFilter
Range(Cells(1, FirstCol), Cells(N, LastCol)).AutoFilter Field:=2, Criteria1:="=*Total*", _
Operator:=xlAnd
' set FiltRng to only visible cells (that passed the "Total" filter)
Set FiltRng = Range(Cells(2, FirstCol), Cells(N, LastCol)).SpecialCells(xlCellTypeVisible)
' modify interior color of all cells at once (one code line)
FiltRng.Interior.Color = RGB(174, 240, 194)
End Sub
You can do with a formula based conditional formatting, using the COUNTIF(a1:f1,"Total") function being >0
Using Range.Find avoids: looping through each row and the need to get the last row.
Instead of applying Range.Find to each row, just apply it to the entire column, no need to check if the cell is empty (see Range.Find Method (Excel) for additional details)
Voici votre code révisé:
Assuming your data is located at `A:F'
Sub forme_couleur()
Const kCriteria As String = "Total"
Dim rTrg As Range, s1stFound As String
With ThisWorkbook.Sheets("DATA").Columns(2) 'change as required
Set rTrg = .Cells.Find(What:=kCriteria, After:=.Cells(1), LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not (rTrg Is Nothing) Then
s1stFound = rTrg.Address
Do
rTrg.EntireRow.Cells(1).Resize(1, 6).Interior.Color = RGB(224, 240, 248) 'RGB(174, 240, 194) give me a green color - changed as required
Set rTrg = .Cells.FindNext(After:=rTrg)
Loop Until rTrg.Address = s1stFound
End If: End With
End Sub
I think I have an issue with the order of my For IF and Next statements, I am trying to only highlight the row where all conditions are meet, instead when my code makes it to the highlighting part all rows are individually highlighted and the code seems to run quite slow, I believe I am performing too many iterations?
Sub SWAPS100()
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Object
Sheets("Output").Activate
With ActiveSheet
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("E2:E" & LastRow) 'new position
If cell = "N" Then
Debug.Print
For Each cell1 In .Range("U2:U" & LastRow) 'Secuirty type
If cell1 = "SW" Then
For Each cell2 In .Range("J2:J" & LastRow) 'prior px
If cell2 = 100 Then
For Each cell3 In .Range("I2:I" & LastRow) 'current px
If cell3 <> 100 Then
'With cell.Interior
With cell.EntireRow.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 6382079
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End If
Next cell3
End If
Next cell2
End If
Next cell1
End If
Next cell
End With
As #Raystafarian commented as I was typing, use And in your if statment instead of all the loops:
Sub SWAPS100()
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Object
Sheets("Output").Activate
With ActiveSheet
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("E2:E" & LastRow) 'new position
If cell = "N" And cell.Offset(, 16) = "SW" And cell.Offset(, 5) = 100 _
And cell.Offset(, 4) = 100 Then
With cell.EntireRow.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 6382079
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End If
Next cell
End With
With looping each row individually it will go slow and will most likely always justify. As long as you have one cell in each column that justifies the if statement then it will color all rows.
Also this can be done with Conditional Formatting with the following formula:
=AND($E2="N",$U2="SW",$J2=100,$I2=100)
While the aforementioned Conditional Formatting with a native worksheet formula is a better solution for 'on-the-fly' updates, a series of AutoFilter methods applied to the columns would be much faster than any procedure involving looping through the cells.
Sub SWAPS100()
Application.ScreenUpdating = False
With Sheets("Output")
If .AutoFilterMode Then .AutoFilterMode = False
With .Cells(1, 1).CurrentRegion
.AutoFilter Field:=5, Criteria1:="N"
.AutoFilter Field:=9, Criteria1:=100
.AutoFilter Field:=10, Criteria1:=100
.AutoFilter Field:=21, Criteria1:="SW"
With .Resize(.Rows.Count - 1, 1).Offset(1, 4)
If CBool(Application.Subtotal(103, .Cells)) Then
.Cells.EntireRow.Interior.Color = 6382079
End If
End With
End With
If .AutoFilterMode Then .AutoFilterMode = False
End With
Application.ScreenUpdating = True
End Sub
Why isnt this text Compare working? I'm trying to compare 2 different ranges from different sheets.
Is there a good simple way of doing this?
Sub selecttest()
Text3 = Sheets("Input DATA").Range(Cells(2, 2), Cells(2, Columns.Count).End(xlToLeft))
Text4 = Sheets("SAP Output DATA").Range(Cells(3, 1), Cells(Rows.Count, 1).End(xlUp))
If StrComp(Text3, Text4, vbTextCompare) = 0 Then
Else
Cells(Cell.Row, "A").Interior.ColorIndex = 26
Cells(Cell.Row, "B").Interior.ColorIndex = 26
Cells(Cell.Row, "C").Interior.ColorIndex = 26
Cells(Cell.Row, "D").Interior.ColorIndex = 26
End If
End Sub
Is there something that im doing incorrectly?
Also tried this with no errors but it wont solve:
Sub comprangetest()
With ThisWorkbook.Sheets("Input DATA")
Text3 = Range(Cells(2, 2), Cells(2, Columns.Count).End(xlToLeft)).Select
End With
With ThisWorkbook.Sheets("SAP Output DATA")
Text4 = Sheets("SAP Output DATA").Range(Cells(3, 1), Cells(Rows.Count, 1).End(xlUp)).Select
End With
'Text3 = Sheets("Input DATA").Range(Cells(2, 2), Cells(2, Columns.Count).End(xlToLeft))
'Text4 = Sheets("SAP Output DATA").Range(Cells(3, 1), Cells(Rows.Count, 1).End(xlUp))
If StrComp(Text3, Text4, vbTextCompare) = 0 Then
Else
ActiveSheet.Cells(Cell.Row, "A").Interior.ColorIndex = 26
ActiveSheet.Cells(Cell.Row, "B").Interior.ColorIndex = 26
ActiveSheet.Cells(Cell.Row, "C").Interior.ColorIndex = 26
ActiveSheet.Cells(Cell.Row, "D").Interior.ColorIndex = 26
End If
End Sub
Am i using the correct method?
Instead of comparing from different sheets, i just brought the range over to the current sheet and made it a requirement to use a selection before the compare initiates. Since the source range is on a row, i used k as the integer for where the source is. The source always changes and is always above the selection. so that line is used for the compare. Of coarse i can probably now even go further and create a selection range from another sheet. But this works for me now. I hope i saved some time for other people struggling with this as i was.
Sub CompareRanges()
application.ScreenUpdating = False
Dim Report As Worksheet
Dim i As Integer, j As Integer, k As Integer
Dim lastrow As Integer
Dim LastColumn As Integer
Dim sht As Worksheet
Dim cell As Range
Dim x As Long, y As Long
Set sht = ThisWorkbook.Sheets("SAP Output DATA")
lastrow = sht.UsedRange.Rows.Count
LastColumn = sht.UsedRange.Columns.Count
'If Selection Is Nothing Then
'MsgBox "nothing selected, please select range."
'Else
'x is the first row number of selection, y is the last.
x = Selection.Rows(1).row
y = Selection.Rows.Count + x - 1
'MsgBox x & " " & y
'give row number of cell above selection.
k = Selection.Rows(1).Offset(-1, 0).row
'MsgBox k
For i = x To y 'lastrow
'For i = 3 To lastrow 'lastrow
For j = 5 To LastColumn
If sht.Cells(i, 1).Value <> "" Then 'This will omit blank cells at the end (in the event that the column lengths are not equal.
'sht.cell (2, j) "k is the variable for where is the source."
If InStr(1, sht.Cells(k, j).Value, sht.Cells(i, 1).Value, vbTextCompare) > 0 Then
sht.Cells(i, 1).Interior.Color = RGB(255, 255, 255) 'White background
sht.Cells(i, 1).Font.Color = RGB(0, 0, 0) 'Black font color
Exit For
Else
sht.Cells(i, 1).Interior.Color = RGB(156, 0, 6) 'Dark red background
sht.Cells(i, 1).Font.Color = RGB(255, 199, 206) 'Light red font color
End If
End If
Next j
Next i
'End If
application.ScreenUpdating = True
End Sub
I jus want to select consequent cells in a single row, until a certain cell, with the value "Total" in it. How do I do this in VBA? I'm making a VBA procedure which relies on the length of the row, which must be dynamic (the length can change).
Sub test()
Dim myRow As Long
Dim rngEnd As Range
Dim rngToFormat As Range
myRow = 4
Set rngEnd = Rows(myRow).Find("total")
If Not rngEnd Is Nothing Then
Set rngToFormat = Range(Cells(myRow, 1), rngEnd)
Debug.Print rngToFormat.Address
Else
Debug.Print "No total on row " & myRow
End If
End Sub
Inside a sub:
For i = 1 To 9999
If ActiveCell.Offset(0, i).Value = "Total" Then Exit For
If ActiveCell.Offset(0, 1).Value = "" Then Exit For
Next
If ActiveCell.Offset(0, i).Value = "Total" Then Range(Cells(ActiveCell.Row, ActiveCell.Column), Cells(ActiveCell.Row, ActiveCell.Column + i - 1)).Select
The macro select from Activecell to the value of "Total".
If you want from the column 5 (sample):
For i = 1 To 9999
If ActiveCell.Offset(0, i).Value = "Total" Then Exit For
If ActiveCell.Offset(0, 1).Value = "" Then Exit For
Next
If ActiveCell.Offset(0, i).Value = "Total" Then Range(Cells(ActiveCell.Row, 5), Cells(ActiveCell.Row, ActiveCell.Column + i - 1)).Select
Sub FindTotal()
Dim rng As Variant
rng = Rows(20) ' Then number of the row where "Total" is. Keep in mind that this will add all columns to rng and which will use a lot of memory. If you can limit the number of columns to be added e.g. rng = Range("A20:Z20") as long as Total will always be within the range
i = 1
While rng(1, i) <> "Total"
i = i + 1
Wend
End Sub