How to highlight a cell based on another cells value VBA? - vba

This question has been asked before but I went about doing it another way. I am trying to highlight a cell if it is greater than the value of another cell.
Here is my code:
Sub Error_Search()
Dim Summary As Worksheet
Dim lr As Long
Set Summary = Worksheets("Summary")
lr = Cells(Rows.Count, 20).End(xlUp).Row
With Summary
For i = lr To 3 Step -1
If Range("L" & i).Value > Range("$Q$2:$R$3").Value Then Range("L" & i).Font.Color = -16776961
Next i
End With
End Sub
Range("$Q$2:$R$3") is a merged cell and it is the cell I want to compare the cell I want to highlight to.
I keep getting a mismatch error.
Any help would be greatly appreciated.
Thanks,
G

As mentioned in the comments, the problem is that a multiple-cells Range doesn't have a single Value, even if the cells are merged: Range.Value yields a 2D variant array whenever more than a single cell is involved. So you can fix the bug by only referring to the top-left cell of the merged range instead.
That said...
You don't need any VBA code to do this; conditional formatting handles it quite neatly.
=$C4>$M$3
Note the $ dollar signs: $M$3 would be your merged cell (only the leftmost cell matters), and $C4 is just the first cell you're defining the conditional format into; leaving the row non-absolute (i.e. no $ on the row number) allows you to apply the format to an entire range of cells by specifying the Applies to range:
Note that the format formula is the same regardless of whether we're looking at $M$3 or $M$3:$N$3 merged cells.
Conditional formats will perform much better than any VBA code you can write.

Related

Copy Formula to a range

Would like to copy a formula from a cell to a range by using variables. It works fine with xlPasteFormulas but want to avoid it. This formula used wrong references so endresult is wrong:
With ActiveSheet
.Range(.Cells(rowStarWs1, colAct), .Cells(rowLast, colAct)).Formula = .Cells(rowSuch2Ws1, colAct).Formula
End With
Example:
Formula is saved in cell C3 (e.g. A3*B3)
Would like to paste the formula to range C10:C13. Range is given by my variables.
Result should look like below (Yellow cells)
I find using R1C1 notation very helpful when moving formulas around, especially in simple cases like the one you illustrated. More consideration is needed for more complex cases.
Sub f()
Dim f As String
f = Range("C3").FormulaR1C1
Range("C10:C13").FormulaR1C1 = f
End Sub
or
Range("C10:C13").FormulaR1C1 = Range("C3").FormulaR1C1
You might use FillDown for this purpose.
Cells(10, 3).Formula = Cells(3, 3).FormulaR1C1
Range("C10:C14").FillDown
FillDown copies the formula from the first cell of the defined range to all its cells. Therefore the first line of code fills that first cell. Assigning the R1C1 format to the Formula property changes the cells referenced in the formula without using the R1C1 format in the output.

Excel VBA - If cells is part of merged cells pass the value?

I'm having some trouble to prepare macro which would help me to pass the value to another cell if the specified cell is a part of merged cells.
As you can see, cells A1-A15 are merged, in B1 I've written =A1 in B2 I did =A2, so what I want to achieve is that whenever I assign somewhere cell which is part of merged cells(A1-A15) the 'test' value is passed so there is no difference if I write =A1 or =A15 or =A10
I would appreciate any help of advice.
You can detect if a Cell is part of a Merged Cell using If Range("A1").MergeCells = True.
Get the number of rows you have in your MergedArea using Range("A" & i).MergeArea.Rows.Count.
More explanation inside the code below.
Code
Option Explicit
Sub CheckifMergedCell()
Dim MergeRows As Long, i As Long
i = 1
While i < 100 ' 100 is just for example , change it later according to your needs
If Range("A" & i).MergeCells = True Then
MergeRows = Range("A" & i).MergeArea.Rows.Count ' number of merged cells
Else ' not merged >> single row
MergeRows = 1
End If
Range("B" & i).Resize(MergeRows, 1).Value = Range("A" & i).Value
i = i + MergeRows
Wend
End Sub
In B1,
=INDEX(A:A, MATCH("zzz", A$1:A1))
Fill or copy down.
what I want to achieve is that whenever I assign somewhere cell which is part of merged cells(A1-A15) the 'test' value is passed so there is no difference if I write =A1 or =A15 or =A10
What you want to accomplish can't be done easily. You could do it with an VBA code that checks every single time you type something, but it's not worth it. The other answer you got here are worth it.
What you want to do is not possible because Excel works in a weird way. Let's say you have cells A1:A15 merged. The value is ALWAYS in first cell of merged area (in this case in A1). So when you reference a cell inside the merged area, it will have a 0 value (a blank cell) always, unless it is the first one.
So my advice, would be:
Use 1 of the other answers, because both are really helpful
If you insist in using normal formulas, then instead of typing =A1, try with absolute references, try =$A$1. If you click and
drag, that formula will work for you to complete adjacent cells to
merged area.
I insist, use 1 of the other answers.

Excel VBA Dynamic Range / Loop issue

I am developing a financial model for a bank and come across the below issue which I am not able to resolve in Excel VBA, and would appreciate your help.
I have built a simple macro which essentially does two things: (i) it clears contents in a given range, (ii) it populates the same range with a formula. In a very abbreviated way it looks like the following:
Sub AutoCalculateCashFlows()
Range(D208:L208).ClearContents
Range("L208").FormulaR1C1 = "=+R[-34]C-R[-34]C[-1]"
Range("L208").AutoFill Destination:=Range("E208:L208"), Type:=xlFillDefault
End Sub
My problem is that the range that should be auto populated is dependent on how many cells did the user fill in within the range of E10:L10. Users will start populating this range from right to left, but I don't know how far they will go from column L to the left. The formula that my macro auto populates needs at least two data, ie. at least L10 and K10 should be populated and if the latter is the case then the macro only needs to auto populate L208 with formula, in case J10:L10 is filled out then the macro needs to auto populate the range L208:K208 and so on to the point that in case the full D10:L10 range is filled out then E208:L208 should be populated with formula.
I have thought to resolve this issue via two routes: (i) approaching it as a dynamic range problem in which case I need a vba code to determine the previous to the last cell populated by the user in the range D10:L10 and use the column code of that cell in "Destination:=Range("E208:L208")", or (ii) run a loop which will populate range E208:L208 with formula until the cell in the previous column within range D10:L10 is filled in by the user and stop when it is not.
Hope this makes sense and thanks in advance for the help.
When you need a dynamic range in VBA, you should simply build one. This is probably the easiest method:
Sub TestMe()
Dim colRange As Long
Dim rowRange As Long
Dim rngMain As Range
rowRange = 10
With Worksheets(1)
colRange = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set rngMain = .Range(.Cells(rowRange, colRange), .Cells(100, 200))
MsgBox rngMain.Address
End With
End Sub
It is dynamic, based on the last used column in row 1 of the first Worksheet.
Concerning the second used column in Row 1, one of these 3 would probably do it for you, depending on what exactly do you want:
.Cells(1, 1).End(xlToRight).End(xlToRight).Column
.Cells(1, 1).End(xlToRight).Column
.Cells(1, 1).End(xlToRight).Column + 1

How to delete rows that had formulas before value paste?

I got an spread sheet that include formulas and I wrote a vb code to value paste.
Depending on the input file number of rows that filled is varied and I need to delete the rows those had formulas and now empty. (This is using as connector and otherwise it some how pick these extra rows which is unnecessary)
Sheet2.Range("G2:G298").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Above code not doing anything...
If the blanks are results of a formula like:
=""
Entered into a cell and then copied and paste as values, those are not really blank cells.
Instead, those are cells that looks blank but contains zero length strings.
SpecialCells(xlCellTypeBlanks) and even Excel formula ISBLANK won't work on it.
One way is to loop through the range and check all that contains "" and delete it.
Dim c As Range, rngtodelete As Range
For Each c In Sheet2.Range("G2:G298")
If Len(c.Value) = 0 Then
If rngtodelete Is Nothing Then Set rngtodelete = c _
Else Set rngtodelete = Union(rngtodelete, c)
End If
Next
If Not rngtodelete Is Nothing Then rngtodelete.EntireRow.Delete xlUp
Another way is using AutoFilter like this:
Sheet2.Range("G2:G298").AutoFilter 1, "="
Sheet2.Range("G2:G298").SpecialCells(xlCellTypeVisible).EntireRow.Delete xlUp
I'm assuming that G2 does not contain your header but the start of your data.
If it happens to be your header, you'll need to use offset when deleting.
Sheet2.Range("G2:G298").Offset(1, 0) _
.SpecialCells(xlCellTypeVisible).EntireRow.Delete xlUp
Sheet2.AutoFilterMode = False
I'm not completely sure what you mean by "This is using as connector", but I believe it has to do with an export/import process to another application.
As mentioned, a zero length string is not the same as a truly blank cell. However, you can rid your worksheet of them easily. The fastest method I am aware of is a quick cyclic run through all of the columns, applying Text-to-Columns ► Fixed width ► Finish to each.
When that is done, the zero length strings will be reverted to truly blank cells but the worksheet's used range will still overlap those empty cells found at the bottom of the dataset. This means that any export to an external program will try to export those cells. Just run .UsedRange to get Excel to reevaluate the actual used range.
First, tap Ctrl+End to see what Excel thinks is the last used cell on the worksheet. Next, run the following macro.
Sub prep_for_export()
Dim c As Long
Debug.Print Sheets("Sheet1").UsedRange.Address(0, 0)
With Sheets("Sheet1")
For c = 1 To .Cells(1, Columns.Count).End(xlToLeft).Column
.Columns(c).TextToColumns Destination:=.Cells(1, c), _
DataType:=xlFixedWidth, FieldInfo:=Array(0, 1)
Next c
End With
Sheets("Sheet1").UsedRange
Debug.Print Sheets("Sheet1").UsedRange.Address(0, 0)
End Sub
Edit Sheet1 in all four places if you have to before running it.
That is a little homogeneous but I think it should work for your purposes. After running the macro, tap Ctrl+End back at your worksheet again to see what Excel thinks is the last used cell on your worksheet. The before and after range addresses were recorded to the VBE's Immediate window as well.

Excel VBA conditional formatting auto-change

Question:
Is there anything that would cause the Formula1 parameter of the FormatConditions.Add method to change automatically, or to change from what is hard-coded in an Excel-VBA macro?
If so, where is the documentation for this behavior?
Description of Problem:
When applying the FormatConditions.Add method to a range, the formula does not match what is specified in the code.
My macro code assigns a formula to a variable named ConditionalRangeFormula. After running the macro the actual conditional formatting formula does not match ConditionalRangeFormula, and the row in the formula does not match the row that was specified in the code. See the "Details" section below for more info.
Hypothesis:
Note 1:
I've noticed that with a range, Excel will automatically "fit" a conditional formatting formula to match the specifics for each cell in a range. For example, in a worksheet with random numbers between 1 and 10 in column A:
I choose column A.
I add a conditional format to column A, with a formula "=IF(A1=2,1)". The cell font is formatted bold red if this formula is true.
Every cell in column A that contains "2" will be bold red, not just cell A1, even though the formula is just for A1.
Is it possible that in the background Excel is doing some changing of my formula in the code above, in an attempt to "guess" what the formula actually should be?
Note 2:
I don't think this is a result of using too many conditional formats for a range. In Microsoft's Excel developer notes for "FormatConditions.Add Method", there is a remark that "You cannot define more than three conditional formats for a range." However, I've successfully added more than three conditional formats with no changes (see details below). Also, I've tested with all other conditional formatting commented out (inactivated), so that only one conditional format is applied, with no changes.
Details:
I'm using Excel 2007 on a Win7 machine.
My code is a little more complex than the example given in the hypothesis above.
The conditional format function is designed to check if a cell in column "AP" is blank, then apply a red outline.
If I place a breakpoint at the With conditionalRange.FormatConditions _.add(xlExpression, , ConditionalRangeFormula) line, I can confirm ConditionalRangeFormula is correct ("=ISBLANK($AP1)"). However, after running, the conditional formatting formula for every cell in the specified range is "=ISBLANK($AP2)". This does what my code specifies.
Please note the working range (ConditionalRange is the code below) actually starts with row 2 of column AP, since row 1 is a header row. As an interesting note, if I make ConditionalRangeFormula "=ISBLANK($AP2)", the conditional formatting formula for every cell in the specified range is "=ISBLANK($AP3)". Notice how the row in the formula is +1 from what is hard coded, just as in the first situation described in the previous paragraph. Interesting behavior, but I can't find documentation for this.
Also, please note that there are four With...End With statements that apply conditional formatting to that cell, before the conditional formatting that gives problems is applied. Each of those first four statements use formulas that work as expected, so I've simplified those code blocks to make the overall code easier to follow. See "Note 2" under the Hypothesis section above for more details.
Here is the code outline:
'define string to identify workbook
Dim w2 As String
w2 = "myworksheet.xlsx"
'define ws2 as worksheet to work on
Dim ws2 As Worksheet: Set ws2 = Workbooks(w2).Worksheets(1)
'define working range
Dim ws2r As range
Set ws2r = ws2.range("E2", ws2.range("E2").End(xlDown))
'add conditional formatting to the working range
With ws2
'see below for .colDiff function
Set ConditionalRange = ws2r.Offset(0, colDiff("E", "AP"))
'The following 4 With...End With statements assign other
'conditional formats, none of which have problems.
'I've simplified these statements to outline what's being done.
'See the last (5th) With...End With statement for
'the unexpected behavior.
WithConditionalRange.FormatConditions _
.add(xlExpression, , ADifferentFormula1)
.Font.Color = someRGBValue
End With
WithConditionalRange.FormatConditions _
.add(xlExpression, , ADifferentFormula2)
.Font.Color = someRGBValue
End With
WithConditionalRange.FormatConditions _
.add(xlExpression, , ADifferentFormula3)
.Font.Color = someRGBValue
End With
WithConditionalRange.FormatConditions _
.add(xlExpression, , ADifferentFormula4)
.Font.Color = someRGBValue
End With
'This With...End With block has unexpected behavior.
ConditionalRangeFormula = "=ISBLANK($AP1)"
With ConditionalRange.FormatConditions _
.add(xlExpression, , ConditionalRangeFormula)
.Borders.color = RGB(192, 0, 0)
End With
End With 'with ws2
Here's the "colDiff" function called in the procedure above:
Public Function colDiff(col1 As String, col2 As String) As Long
With ActiveSheet
'return the number of columns between col1 and col2
colDiff = Abs(.range(col1 & "1").Column - .range(col2 & "1").Column)
End With
End Function
I tested this functionality by placing a header "Data" in AP1, placing random data from AP2 to AP16, then deleting AP1,5,7,13 to make BLANKS and the following worked correctly:
Public Sub Test()
With Range("E2:AP16").FormatConditions.Add(xlExpression, , "=ISBLANK($AP2)")
.Borders.Color = RGB(192, 0, 0)
End With
End Sub
Does the above single function work correctly for you? If not, I would suspect that perhaps there are merged cells or some other spreadsheet specific issue going on.