I have a FormatCondition. I am reading the .Formula1 and the .AppliesTo
I want to find if the Formula contains a cell reference that will change across the range specified by the AppliesTo, eg =NOT(ISNUMBER(C3)) in a range C3:D10.
From what I can tell, that reference might be relative (eg C3) or mixed (eg $C3 or C$3) but not absolute. It will also be the 'top-left most cell in the applied range' based on https://www.ablebits.com/office-addins-blog/2014/08/07/relative-absolute-cell-references-excel-conditional-formatting/ and some other sites.
If the range is something like C3:D10 then that's easy. Find the top left using eg myRange.Cells(1, 1), convert it to a string using .Address or similar and then look for that string in the Formula, along with relevant variations adding a $. Sure, I'd have to be careful about things like strings (eg top left cell is C3' and formula is="CC3NE"`), but it's possible (still, I'd welcome suggestions on how to do that better, but that's not the question).
The real problem is if the range is more complex, as seems to happen often with Conditional Formatting. An example is $CQ$39:$FT$39,$BE$39,$BE$8:$BE$9,$CU$8:$FT$9,$CU$12:$FT$14,$BE$12:$BE$14,$BE$16:$BE$30,$CQ$16:$FT$30,$CQ$32:$FT$36,$BE$32:$BE$36. .Cells(1, 1) doesn't give the right answer for that (BE8, according to the formula that Excel made).
Further, what if the range were something like $A$5,$E$1 - there is no 'top left'. So how does excel (or the user) decide which should be in the formula?
Thus the primary question is: What is the system for Excel determining which cell to use in a formula, because I don't believe it is 'top left' - it might be 'find the topmost row, then find the leftmost cell there', or it might be the reverse, or something completely different.
The second question is: how best can I find that cell from a given range?
The bonus question (I'm happy if this doesn't get answered here) is: Is there a good way to then find references to that cell in a formula, including relative and mixed versions of the cell?
Note that these strange ranges are coming about from Rows and Columns being Cut and Pasted on a sheet with Conditional Formatting, with Excel chopping up the conditional formatting as a result (changing the range, and changing the formula, both without user input). So the priority is to deal with whatever Excel would set the formula to be on its own in such a scenario, not necessarily what a user might do - but handling both would be even better.
Thanks for updating your question and find below my comments
What is the system for Excel determining which cell to use in a formula, because I don't believe it is 'top left' - it might be 'find the topmost row, then find the leftmost cell there', or it might be the reverse, or something completely different.
Usually range in Excel is similar to a box or rectangle with a fixed length and width, e.g. B3:C8. In case of this simple box type ranges the top left most cell is the base for all formulas in conditional formatting. In other words at first formula evaluation this cell's value is checked against the formula applied in conditional formating. (Let’s call this cell as mother cell)
For example
If conditional formatting is applied to cell A1:D10 and a conditional
formula is B2 > 0, it means apply formatting to cell A1 if value of
B2 > 0, and for others apply formatting to any cell if value of a
cell with an offset of (1, 1) (that was B2 in A1 case) has value
greater then 0. i.e for formatting of B2 value of C3 will be checked.
If conditional formatting is applied to cell A1:D10 and a conditional
formula is AND($B1 >= 30, $B1 <= 60) it means apply formatting to
cell A1 if value of condition is true, but now the difference comes,
because B is now static because of $B, for conditional formatting of
B2 the condition will again be AND($B1 >= 30, $B1 <= 60) same for C1
and D1, but for A2, B2, C2 and D2 it will be AND($B2 >= 30, $B2 <=
60)
In first case the first cell that was checked against the formula was A1 and even in second case the cell that was checked against the conditional formula was A1 (which we called mother cell)
Now if the range is not like a box, it is a mixed range separated by commas, even in this case if we make a box around that range the mother cell is the cell in upper left corner, it is not the first cell of the range but first cell of the box.
For your 2nd question how best can I find that cell from a given range?
If you want to find the mother cell in a box like simple Range, it is just cells (1, 1)
If you want to find that cell in mixed range may be there are some functions out there but I don’t know of any; I would find that by using loop like below
Sub find_topleft()
Dim r, full_range As Range
Set r = Range("$O$8:$O$17,$Q$4:$Q$13,$S$4:$S$6")
Set full_range = Sheets("Sheet1").UsedRange
row_num = full_range.Rows.Count + full_range.Row - 1
col_num = full_range.Columns.Count + full_range.Column - 1
For Each c In r
If c.Row < row_num Then
row_num = c.Row
End If
If c.Column < col_num Then
col_num = c.Column
End If
Next
Debug.Print row_num
Debug.Print col_num
End Sub
Is there a good way to then find references to that cell in a formula, including relative and mixed versions of the cell?
That cell is directly linked with the formula as stated in answer to your first question.
First answer:
Short version: Excel does indeed use the most top left cell - but it does that EVEN IF THE CELL IS NOT PART OF THE RANGE.
I created a blank sheet, selected A5,E1, and put in a conditional format of NOT BLANK (which Excel does with a formula). Excel created the following:
Range: $E$1,$A$5
Formula: =LEN(TRIM(A1))>0
So even though A1 is not part of the range, that's what got used in the formula.
I checked this by duplicating it around the sheet, and it stayed consistent.
Thus Excel finds the leftmost column in the range, and the topmost row in the range, and combines them to produce the cell that should be considered the 'top left' of the range, even if the resulting cell is not actually part of the range.
This suggests an answer to the second question too: Find the top most row in the range; find the left most column; then use a cell that combines the two to compare with the formula. You could do that by going through the range string, or maybe cell by cell through the range itself; perhaps there is a better way to do it (suggestions welcome).
It's not pretty, but it would work, if I can find a good way to do those two things.
I would still welcome:
anyone who can improve on this answer about which cell is used in the formula (I did not test this extensively)
anyone who can suggest a good way to find the 'top left cell' as above
anyone who can suggest a good way to search the formula string for that top left cell
EDIT - Here's an alternate code method to Usmanhaq's excellent method - this goes through the range as a string:
Private Function FindTopLeft(rangeStr As String, rowabs As Boolean, colabs As Boolean) As String
newRange = Replace(rangeStr, ":", ",")
newRangeArray = Split(newRange, ",")
Dim lowestRow As Long
Dim lowestCol As Long
lowestRow = 2147483647
lowestCol = 2147483647
For Each cell In newRangeArray
cell = Trim(cell)
If cell <> "" Then
cCol = range(relativeCell).Column
cRow = range(relativeCell).Row
If cCol < lowestCol Then lowestCol = cCol
If cRow < lowestRow Then lowestRow = cRow
End If
Next
FindTopLeft = Cells(lowestRow, lowestCol).Address(rowabs, colabs)
End Function
Related
I'm looking for a way by VBA or whichever works, even 1 command button but 4-5 processes to be called
Call process1
Call process2
End Sub
on one click which somehow seems impossible for me as I'm not that advanced in Excel VBA, but hopefully this challenge is a piece of cake for others. The task is to highlight cells horizontally by range based on the formula referring to a cell in Column AM. So "B8" is an amount of 100 which needs to be divided by the number of partitions appearing on "AM3". So 100/6. Now "AM3" is 6 so starting from "C8" a number of 6 cells (Merged in 4's) will be highlighted horizontally. "C9" is relating to "AM4" which is having a value of 9 and will highlight 9 cells (Total of 36 cells since merged) horizontally .
For now this is what i have applied but it limits to only within that range :
Sub HighlightRangeOfCells()
Dim rng As Range
For Each rng In Range("C8:AL12")
If IsNumeric(rng.Value) Then
If rng.Value <> 0 Then
rng.Interior.Color = vbRed
End If
End If
Next rng
End Sub
Thanks for your efforts and reply whatever it may be if possible or not.
As mentioned by SSlinky, the best way to do this is using conditional formatting. I have created a simple Excel sheet for explaining you how to do such a thing: I have put the formula =COLUMN()<=$J1 in cell "A1", I have used this formula for conditional formatting, I have dragged to the right, and then I have dragged down.
This is what it looks like:
As you see, cells get highlighted when their column number in some way corresponds with the value of column "J". All you need to do is replace "J" by "AM" and describe the correspondence as you see fit.
For your information: in the formula, I'm using the reference $J1, which means that while dragging and dropping, the row number might change, but the referred column always needs to be "J" (it's a combination of absolute and relative cell references).
I have an attendance form. Cells A1-G1, which will get an X for present. I have it set up to calculate the attendance percentage. I also have it set up to change the calculation based on number of days eligible ie new person starts mid month, they would only have 15 days, changing the numerator. I have to manually change the range for the countif statement.
A1:G1 is the range
J1 is the area we'd put in for how many days eligible (this is for those who are not on the whole term)
I3 is the default days eligible (regular whole term)
=COUNTIF(A1:G1,"X")/(IF(J1="",I3,J1))
This works fine, I'd like to set it up to change the countif to only count the range that has white cells vs other colors. Change the A1:G1 to say C1:G1 if cells A1, B2 were red.
I can explain for if needed. I see lots on how to change the color of a cell, but not to act on a color in countif.
D
Excel doesn't have in-built functionality for handling colors within formulas. You need to use VBA. But a note of caution, the following UDF won't recalculate unless you manually refresh. The proposed solution also uses SUMPRODUCT instead of COUNTIF:
Public Function HasNoFill(ByVal rng As Range) As Boolean()
Dim temp() As Boolean
ReDim temp(1 To rng.Count)
Dim cell As Range
For Each cell In rng
Dim i As Long
i = i + 1
temp(i) = cell.Interior.Color = 16777215
Next
HasNoFill = temp
End Function
I have a row and I want to sum only visible cells, i know if it's a column I can use subtotal (109,range), but this one doesn't seem to work for cells in one row. Anyone knows how to sum only visible cells in a row?
Please click here for picture
If a VBA solution is okay, this will work:
Function sumVisible(rng As Range) As Double
Dim cel As Range
For Each cel In rng
If cel.EntireColumn.Hidden = False Then
sumVisible = sumVisible + cel.Value
End If
Next cel
End Function
Pretty straightforward - just checks if a cell in your range has a hidden column, if it's visible, sum it.
=sumVisible(D2:M2) is how you'd use it.
You can check the width of the cell.
=IF(CELL("width",A1)=0,"hidden","open")
you can then sum your cells as need it using IF and CELL
=IF(CELL("width",A1)=0,0,A1)
more info below:
Ignoring a hidden column in an excel sum formula
You can do this using a single worksheet formula alone, provided that none of the columns which remain unhidden will have a width of less than or equal to 0.5 (which, in practice, would be so narrow as to be virtually hidden in any case).
Assuming a range of A1:E1
=SUMPRODUCT(0+(CELL("width",OFFSET(A1,,N(INDEX(COLUMN(A1:E1)-MIN(COLUMN(A1:E1)),,))))>0),A1:E1)
Unfortunately this formula will not update automatically as changes regarding hiding/unhiding columns within the range are made. As such, it will be necessary to 'recommit' it each time you make changes in that respect; one way to do this is via going into the formula as if to edit it and then recommitting by pressing ENTER.
Perhaps of interest is this post.
Regards
This is just part of my code. the value from the textbox here already gets copied to the specific cell in the Bank Certification worksheet. I need to make sure that cell C5 is specifically fitted regardless of the length of the text i inputted in the textbox. I tried interchanging range with cells to no avail. This problem seems so simple but I don't know why it doesn't work...
Dim counterparty As String
counterparty = Sheet1.txt1.Text
Range("C5").Value = counterparty
Sheets("Bank Certification").Select
Range("C5").Select
Selection.AutoFit
Try
Dim counterparty As String
counterparty = Sheet1.txt1.Text
Range("C5").Value = counterparty
Sheets("Bank Certification").Select
Columns("C:C").Autofit
Other answers correctly state that AutoFit must be used with a column, not just a cell. However, there are some nuances to using AutoFit that I didn't understand until I started experimenting.
Either of the first two statements below will use all values in column C to AutoFit the width of the column. That means if there is a value in some other cell in column C (for example C10) that is wider than the value in C5, it will fit the column to the widest cell in column C (for example C10).
Range("C5").EntireColumn.AutoFit ' Will fit to widest cell in column
Range("C:C").AutoFit ' Will fit to widest cell in column
If you want to just fit the column on 1 cell (or a certain range of cells, but not the whole column or columns), use a statement like this:
Range("C5").Columns.AutoFit ' Will fit column C to width of cell C5
And of course, it's always better form to write code like this when you can:
Fully qualify the range unless you're absolutely sure you'll only be working with one worksheet
Use Named Ranges or Range objects.
For example:
Workbooks("MyWorkbook.xlsm").Sheets("Sheet1").Range("MyData").Columns.AutoFit
' or
Set AutoFitRange = Workbooks("MyWorkbook.xlsm").Sheets("Sheet1").Range("C5")
AutoFitRange.Columns.AutoFit
I suppose this should be easy, but - how do I extract a value from each cell in a range, place that value in a formula, and return the result in the same cell that the original value came from?
Example: (simplified :-))
I already have values entered in a range (say A1:A3): A1=2.1 ; A2=0.78 ; A3=1.1. I also have a specific factor in D1 e.g. D1=0.4, and a specific formula that I want to use: exp(ln(value)/factor). What I want to do is:
extract the value in A1 (=2.1) and
place it in the formula together with the factor in D1 (=exp(ln(2.1)/0.4))
and put the result back in A1 (=6.39)
...and so on for A2 (=0.54), A3 (=1.27)......
As my range is very large, covering several sheets, I´m thinking some kind of "for each cell in range(myRange)" function, but I haven´t been able to figure it out...
To accomplish this, try the following:
Dim rng As Range, Cell As Range
Then set your Range:
Set rng = Range("A1:A3")
Then begin your For Each loop:
For Each Cell In rng
Cell = Exp(Log(Cell)/Range("D4"))
Next Cell