Calculation of values based on the color of cells in Excel VBA - colors

The code shows a simple average calculation based on the values in the defined cells. Those cells are highlighted in three colors. The aim is to take the values into the calcuation which cell color is e.g. green. I know the "if" command is needed, I just dont know where excatly to put it in:
Dim wb As Workbook, wq As Object
Dim ws As Worksheet, datdatum
Dim cell As Range, cell2 As Range, col As Long
ws.Range("H104:U104").Formula = "= Average(H34,H39,H68,H71,H83)"

I'll assume that entire rows are not green and that each column needs to be looked at independently.
Loop through each column from H to U. Loop through each cell in each column. Build a union of the cells that are green and average the union. Move on to the next column.
There is no point in building a formula for each column since any change would require rerunning the sub procedure. These will work on both manually set and conditional formatted cell colors.
.DisplayFormat does not work within a User Defined Function.
dim c as long, r as long, rng as range
with worksheets("sheet1")
for c =8 to 21
for r=2 to 103
if .cells(r, c).displayformat.interior.color = vbgreen then
if rng is nothing then
set rng = .cells(r, c)
else
set rng = union(rng, .cells(r, c))
end if
end if
next r
if not rng is nothing then _
.cells(104, c) = application.average(rng)
'alternate
'if not rng is nothing then _
'.cells(104, c).formula = "=average(" & rng.address(0,0) & ")"
next c
end with
Alternate,
dim c as long
with worksheets("sheet1")
if .autofiltermode then .autofiltermode = false
for c =8 to 21
with .range(.cells(1, c), .cells(103, c))
.AutoFilter Field:=1, Criteria1:=vbgreen, Operator:=xlFilterCellColor
.cells(104, c) = application.subtotal(101, .cells)
.AutoFilter
end with
next c
end with

Related

VBA - Highlight/Delete row if Range is Empty

I have a range of data, with CASE ID's in Column A, and Issues (1 through 10, or Columns B through K) in Columns B onwards.
Once certain issues are ruled out as 'normal', they would be removed from the Issues sheet based on their respective column. For ex: CASE ID #25, Issue 4 is ruled OK, then it would be deleted from Row 25, Column 5 (or Column E) but the CASE ID would remain.
The goal is that by doing this check after the fact, it may leave certain rows entirely blank, from Column B onwards (since the CASE ID would already be there.)
My code doesn't function successfully. Once run, it highlights several rows that are not entirely blank in the target range.
I'm trying to pinpoint rows in the range B2:P & lastrow where the entire row is blank, and then highlight these rows and subsequently delete them.
Code:
Public Sub EmptyRows()
lastrow = Sheets("Issues").Cells(Rows.Count, "A").End(xlUp).row
On Error Resume Next
Sheets("Issues").Activate
For Each rng In Range("B2:P" & lastrow).Columns
rng.SpecialCells(xlCellTypeBlanks).EntireRow.Interior.ColorIndex = 11
'rng.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Next rng
Application.ScreenUpdating = True
End Sub
The purpose of first highlighting is to test the code works. If successful, they would be deleted entirely.
Your description says Columns B through K, but your code has B through P...
You can do it like this (adjust resize for actual columns involved):
Public Sub EmptyRows()
Dim lastRow As Long, sht As Worksheet, c As Range, rngDel As Range
Set sht = Sheets("Issues")
For Each c In sht.Range(sht.Range("A2"), sht.Cells(Rows.Count, 1).End(xlUp)).Cells
If Application.CountA(c.Offset(0, 1).Resize(1, 10)) = 0 Then
'build range to delete
If rngDel Is Nothing Then
Set rngDel = c
Else
Set rngDel = Application.Union(rngDel, c)
End If
End If
Next c
'anything to flag/delete ?
If Not rngDel Is Nothing Then
rngDel.EntireRow.Interior.ColorIndex = 11
'rngDel.EntireRow.Delete '<< uncomment after testing
End If
End Sub
Once run, it highlights several rows that are not entirely blank in the target range.
This is because you are selecting all blanks, instead of only rows where the entire row is blank.
See the code below
Public Sub EmptyRows()
With Sheets("Issues")
lastrow = .Cells(Rows.Count, "A").End(xlUp).row
Dim rng as Range
For Each rng In .Range("B2:B" & lastrow)
Dim blankCount as Integer
blankCount = Application.WorksheetFunction.CountA(rng.Resize(1,.Range("B:P").Columns.Count))
If blankCount = .Range("B" & lastRow & ":P" & lastRow).Columns.Count Then
Dim store as Range
If store Is Nothing Then Set store = rng Else: Set store = Union(rng, store)
End If
Next rng
End With
store.EntireRow.Interior.ColorIndex = 11
'store.EntireRow.Delete
End Sub
Gathering the ranges first and then modified them (changing color or deleting) will help to execute the code faster.
Here is another approach, using CountA
For Each cell In Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row)
Dim rng As Range
Set rng = Range("A" & cell.Row & ":" & "P" & cell.Row)
If Application.WorksheetFunction.CountA(rng) = 1 Then
rng.EntireRow.Interior.ColorIndex = 11
End If
Next cell

VBA- Alter a different cell with multiple cell values

Using VBA in excel, I am wanting to incorporate the formula located in column "O", shown below, for all B rows that have a value starting at B9. Please reference the image.
=""&D9&" "&I9&" (MK NO. "&B9&")"
This should do what your are looking for.
Sub Pasteformula()
Dim LookupRange As Range
Dim c As Variant
Application.ScreenUpdating = False
Set LookupRange = Range("B9:B500") ' Set range in Column B
For Each c In LookupRange 'Loop through range
If c.Value <> "" Then 'If value in B is empty then
Cells(c.Row, 15).FormulaR1C1 = _
"=""""&RC[-11]&"" ""&RC[-6]&"" (MK NO. ""&RC[-13]&"")""" 'Apply formula
End If
Next c
Application.ScreenUpdating = True
End Sub
Set the range and enter the formula, then change the range to values.
Sub Button1_Click()
Dim rng As Range
Set rng = Range("O9:O" & Cells(Rows.Count, "B").End(xlUp).Row)
rng.Formula = "=CONCATENATE(D9,"" "",I9,"" (MK NO. "",B9,"")"")"
rng.Value = rng.Value
End Sub
from your narrative I get that you already have the proper formula in O9, hence you could use AutoFill() method of Range object:
Range("O9").AutoFill Range("B9", Cells(Rows.Count, "B").End(xlUp)).Offset(,13)

Deleting cells and corresponding row if criteria is met

I have a spreadsheet that has columns from A5 to AA5 and has data from A6 to AA10000. In cells A1, a user inputs a value, in cell A2 is a drop box that contains the headers of columns X to AA (A, B, C, D), and in A3 I have a dropdown of logical operators (<,>,<>,=). I'm trying to write a script that goes through columns X to AA and remove the cells that met a criteria that a user sets, e.g. user inputs a value of 300, a header "B" and a logical operator "<" and the macro goes through column Y which has the header "B" and deletes all values that are less than 300, the deletes the row from A to AA.
So far I've attempted this:
Sub removedata()
Dim ws As Worksheet
Dim rng As Range
Dim headerval As Variant
Dim sign As Variant
Dim inputval As Variant
Dim b_header As Range
Dim Cell As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("X5:AA5000")
Set b_header = ws.Range("X5:X5000")
inputval = cells(1, 1).Value
headerval = cells(2, 1).Value
sign = cells(3, 1).Value
For Each Cell In b_header.cells
If (headerval = "B") And (sign = "<") And (inputval < Cell.Value) Then
Cell.Delete
End If
Next Cell
End Sub
I've only attempted it for B column as a test to see whether or not I could get something to happen. When I run this Macro, it just buffers for a second and then nothing else happens.
Any help would be greatly appreciated!
Edit: Actually I realised it deletes the values that are greater than the input (Cell A1), however it only deletes a few of them each time I run it, it also moves the cells below it to its position.
The COUNTIF/COUNTIFS worksheet function accepts and interprets criteria as strings. You can use with Evaluate or directly through an application object.
Option Explicit
Sub delSpecial()
Dim lr As Long, i As Long, c As String, cl As Long
With Worksheets("sheet6")
c = .Cells(3, "A").Value & .Cells(1, "A").Value
cl = Application.Match(.Cells(2, "A").Value, .Rows(5), 0)
lr = Application.Max(.Cells(.Rows.Count, "X").End(xlUp).Row, _
.Cells(.Rows.Count, "Y").End(xlUp).Row, _
.Cells(.Rows.Count, "Z").End(xlUp).Row, _
.Cells(.Rows.Count, "AA").End(xlUp).Row)
For i = lr To 6 Step -1
If CBool(Application.CountIf(.Cells(i, cl), c)) Then
.Cells(i, "A").Resize(1, 27).Interior.Color = vbYellow
'.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub

Filtering for the value in A1

I am trying to figure out a way to filter Column C for the value in A1, then put the formula in the first cell and copy down. I have the below code but I can't seem to get it to work. I have an example of the spreadsheet below the code.
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:="=RC[1]"
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
With .Columns(2)
.Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=RC[1]&""-R21"""
End With
End If
End With
I think the problem is that your formula is only being added to the first cell in your filtered range. That is because a discontiguous SpecialCells range such as yours, i.e., C7, C10,C12:C15, etc., will consist of multiple Areas. If that's the case, you need to loop through the Areas with a For/Next:
Dim FilteredArea as Range
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:="=RC[1]"
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
For Each FilteredArea in .Columns(2).Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Areas
FilteredArea.FormulaR1C1 = "=RC[1]&""-R21"""
Next FilteredArea
End If
End With
This is untested, but hopefully will give you an idea of how to work with Areas.
Set range("A1") as a variable
Sub Button2_Click()
Dim F As Range'declare F as a range
Set F = Range("A1")'set F as range("A1")
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:=F'Filter for F
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
With .Columns(2)
.Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=RC[1]&""-R21"""
End With
End If
End With
End Sub
Here's another version, so you won't have to use Formulas.
Sub LoopThroughFilterd()
Dim rws As Long, rng As Range, Fltr As Range, c As Range
rws = Cells(Rows.Count, "A").End(xlUp).Row
Set rng = Range("C6:C" & rws)
Set Fltr = Range("A1")
Application.ScreenUpdating = 0
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:=Fltr
For Each c In rng.Cells
If c.EntireRow.Hidden = 0 Then
c.Offset(, -1) = c & "-R21"
End If
Next c
.AutoFilter
End With
End Sub
You can also Loop through the cells instead of filtering.
Sub LooPFor()
Dim rws As Long, rng As Range, Fltr As Range, c As Range
rws = Cells(Rows.Count, "A").End(xlUp).Row
Set rng = Range("C6:C" & rws)
Set Fltr = Range("A1")
For Each c In rng.Cells
If c = Fltr Then c.Offset(, -1) = c & "-R21"
Next c
End Sub

Highlighting duplicates based on data within the same column

I'm trying to create a macro that searches the B column to find duplicates of the same string, and then highlights said duplicates from columns A to I
I've managed to create something that highlights the correct cells but does not seem to be able to find the duplicates. Not entirely sure where I've gone wrong but I think it could be because I'm adapting a former macro that looked across two sheets
Code:
Sub Duplicate()
Dim rng1 As Range, rng2 As Range, rng3 As Range, i As Long, j As Long
Dim w1 As Worksheet
Set w1 = Worksheets("Sheet1")
For i = 1 To w1.Range("B" & Rows.Count).End(xlUp).Row
Set rng1 = w1.Range("B" & i)
For j = 1 To w1.Range("B" & Rows.Count).End(xlUp).Row
Set rng2 = w1.Range("B" & j)
Set rng3 = w1.Range(Cells(ActiveCell.Row, 1), Cells(ActiveCell.Row, 9))
If StrComp(Trim(rng1.Text), Trim(rng2.Text), vbTextCompare) = 0 Then
rng3.Interior.Color = RGB(168, 188, 255)
End If
Set rng2 = Nothing
Next j
Set rng1 = Nothing
Next i
End Sub
At the moment I see one problem, you are referring to Activecell, However you never activate or select any cell nor range. This makes the color change on a cell that you have selected when running the macro and no other. If you replace activecell.row with variable i the macro should be working fine.
Does this have to be within VBA? The conditional formatting feature in Excel can do this without having to rely on a macro. This should also refresh faster than running the VBA. For this you have to rely on relative references within the conditional formatting, which are relative to the activecell at the time you set up the rule.
Select your data from A:I
Conditional formatting> new rule
Select 'use a formula to determine which cells to format'
Use the formula =COUNTIF($B$1:$B$6,$B1)>1, replacing the first variable with your entire range in column B. The single dollar sign on reference $B1 is very important as it tells it to check column B regardless of which column the formatting is being applied to.
You are always setting rng3 to the same cells, because you never change the active cell. Also, you don't really need to have an extra range because you are already looping through the cells.
Sub Duplicate()
Dim rng1 As Range, rng2 As Range, rng3 As Range, i As Long, j As Long
Dim w1 As Worksheet
Set w1 = Worksheets("Sheet1")
For i = 1 To w1.Range("B" & Rows.Count).End(xlUp).Row
Set rng1 = w1.Range("B" & i)
For j = 1 To w1.Range("B" & Rows.Count).End(xlUp).Row
If j <> i Then
Set rng2 = w1.Range("B" & j)
If StrComp(Trim(rng1.Text), Trim(rng2.Text), vbTextCompare) = 0 Then
rng1.Interior.Color = RGB(168, 188, 255)
rng2.Interior.Color = RGB(168, 188, 255)
End If
Set rng2 = Nothing
End If
Next j
Set rng1 = Nothing
Next i
End Sub

Resources