Find Address of cell from Index match VBA - excel

The below Code finds the value of a certain cell without any problem. However I am not interested in the value. What I need is the Cell Address. I wish to later in the code use this new found address to adjust it value a few times depending on different factors.
I could use the Address function if this was not in VBA but I have not found a way to use it or anything similar in VBA.
Sub IndexMatch()
A = Application.WorksheetFunction.Index(Workbooks("AllSwipes.xlsx").Worksheets("Backend").Range("H1:CY1"), 1, Application.WorksheetFunction.Match(SomeGlobalVariable, Workbooks("AllSwipes.xlsx").Worksheets("Backend").Range("H1:CY1"), 0)).Offset(1, 0)
MsgBox A
End Sub

Turns out it was as simple as adding .Address to my code Thanks #ScottCraner for pointing me in the right direction.

Related

VBA Range statement using active column

I need to use my active column in my range statements. How to write down this:
Range((Activecolumn)2)
So I need a column value to be dynamic because I am moving left and right by pressing a userform button, but the row number always stays the same. At first I am working with column "C" and select it with
Columns("C").Select
and I navigate the selected column with
Private Sub Next_Format_Button_Click()
ActiveCell.Offset(, 1).EntireColumn.Select
End Sub
So when I navigate to the next column I need all my other range statements to go along with it. So basically the column letter in my range statements should be something like "current" or "active" column.
Could someone, please, help me?
Range(ActiveCell.address).entireColumn.copy
Is what you are looking for I think?
I'd also recommend avoiding ".Select" unless absolutely necessary. It is adding unnecessary lines to your code and leaves the program at greater risk of inadvertent user corruption by selecting another range via mouse before the copy (or whatever) operation completes. Better to go straight to whatever operation you intend to do, or by assigning the range to a variable.
edit: Ah, sorry, I see now your only looking row 2, then its Cells(2, ActiveCell.Column) as pointed out above.
If you want to get the Number of the column where you selected something:
ActiveCell.Column
If you need the letter of the column your selection is in:
Split(ActiveCell.Address, "$")(1)

Automatically adjust the "RC" in an English formula based on the user's client language

So I was surprisingly getting error reports from many users for a new tool I made. Those users all have the German version of Excel installed. After a quick glance, I figured out the problem:
I used this formula as a named function to get the color of the adjacent cell (don't ask me why that's important, but things depend on the result):
=GET.CELL(63;OFFSET(INDIRECT("RC";FALSE);0;1))
Now in the German version, the "RC" remains, but would have to change to "ZS" for the formula to not throw a reference error.
It's written the way it is to reference the cell the function is in.
Is it possible to rewrite this formula in a way that does not "hard code" the "RC" so it can change depending on the localization of the user (Chinese and Czech would be relevant too)? Or is it possible to replace the named formula with a bit of VBA code that can check for the language version of the user?
If I can't adjust this bit of the tool I'll have to go with a less attractive workaround (Have multiple Y/N checks instead of assigning colors).
Well, this may not actually answer my question, but it does solve my problem. Turns out that entering
=GET.CELL(63;Sheet!B1)
In the name manager while having A1 selected delivers exactly the same result as
=GET.CELL(63;OFFSET(INDIRECT("RC";FALSE);0;1))
Being that it gets the cell color number from the cell one to the right, no matter where you then insert this function.
You can then find the user's LCID using a vba code such as
dim lcode as long
lcode = Application.LanguageSettings.LanguageID(msoLanguageIDUI)
You can then us a simple if then else and connect the LCID to appropriate strings using (this). Example:
If lcode = "0407" Then
Cells(5, 5).Formula = "=GET.CELL(63;OFFSET(INDIRECT(""ZS"";FALSE);0;1))"
ElseIf lcode = "1033" Then
Cells(5, 5).Formula = "=GET.CELL(63;OFFSET(INDIRECT(""RC"";FALSE);0;1))"
End If
Alternatively, you can also define a string i and based on the LCID you can attach i the appropriate value based on the result and use:
Cells(5, 5).Formula = "=GET.CELL(63;OFFSET(INDIRECT(" & i & ";FALSE);0;1))"
This is easily solved with a UDF
Option 1: pass the cell you want the color of as a parameter (this cell can be anywhere, not limited to the next cell to the right)
Function GetColor(r As Range) As Variant
Application.Volatile
GetColor = r.Interior.ColorIndex
End Function
Option 2: get the color of the next cell to the right of the cell containing the formula
Function GetColorNextCell() As Variant
Application.Volatile
GetColorNextCell = Application.ThisCell.Offset(, 1).Interior.ColorIndex
End Function
That said, using format as data is a bad idea. Both these formula (and your named range version) won't update when you just change the color of a cell. They all required you to force a recalc to update (changing format does not trigger a recalc).
I've made them Volitile so they at least update on all recalcs, but even then they won't update if you just change the color.
You are representing something with that color. I'd suggest you change that to use a specific value in the cell to represent whatever that is. You can always use Conditional Formatting to also color the cell based on that value.

How to use relative names in Excel VBA

Many "advanced" (aka: VBA) excel tutorials on the web or even excel's vba help encurage us to use the
Range("B2:B10")
method (to be precise: object) for selecting cells or getting values. In the same place they often add it's totally ok to use predefined names as well:
Range("valuesabove")
On the other hand I fell in love with the incredible power of relatively defined cell names. They make it so much easier to write and handle big composite formulas, and basically to refer to nearly anything.
However, relative names don't work in the Range("valuesabove") method the way we are used to it.
Usually (when used on the worksheet) relative names are relative to the currently selected cell or to the cell in which they are used.
In VBA's Range() object this is not true. Range is relative to a WorkSheet object, by default to the ActiveSheet. But ActiveSheet is represenetd by its leftupper cell, A1. And this is what Range turns out to be relative to. And this is why absolute names ($C$23) do work with it, and relative ones ("one column to the left, two rows up") don't.
So my question is:
How can I harness the power of relative names in VBA then?
EDIT:
Realising that my question was rather unclear (thx's go to you guys commenting tirelessly) let me try to put it in a specific form and clarify terms:
IMHO on an excel worksheet it is very comfortable to use names in order to refer to cells or define calculated values by functions based on cell values.
In excel a reference to a cell can be either relative, absolute, or mixed. This is true also when creating names. Thus we can speak about absolute, relative or mixed names (in terms of referring of course).
Here an absolute name is used a couple times (created using excel's Trace Dependents function):
Name "name" = $D$2
A relative name is used a couple times here:
Name "upright24" while, e.g. cell A7 is selected = C3 (without $ signs!). But this changes constantly according to the selected cell or region. You can check it in the name manager! (Ctrl+F3)
And this is what we can consider as a mixed name:
Name "rel_serialnumber" while, e.g. cell C6 is selected = $B6. The row of which (6) changes constantly according to the selected cell or region.
The creation of a relative or a mixed name is explicitly based on the active cell at the moment of creating the name. The creation of an absolute name naturally doesn't rely on the cursor position.
Note, that
absolute names mean a dinamic offset from the referenced cell, which is one and only
relative names mean a static offset from the referenced cell, which thus changes always corresponding to the place where the name is used
mixed names mean a mixed (or half-dynamic) offset from the referenced cell, the row or column of which thus changes always corresponding to the place where the name is used while the other remains always the same (the offset in one or the other direction remains zero).
Okay, now here is the thing. I have a database-like excel sheet where I handle the rows like records and the columns as fields for properties. The user uses this thing as follows: he "selects a record" by placing the cursor in any cell of the row of the desired record. Then he presses a big command button which starts my VBA macro. This intends to open a prepared skeleton file and fill some specific cells in it (which are btw defined by absolute names) with some values (which are defined by mixed names) from the selected record.
Since Range("name") is considered ok to use in VBA (see above) I thought Range("relativename") or Range("mixedname") will work just as fine while automatically relying on the active cell.
I couldn't be worse.
Only Range("absolutename") works in the way one would expect! Explanation see above.
So I'm after a function / method / object that is possibly as comfortable to use with a "relativename" or a "mixedname" as Range("absolutename") is.
It appears you are looking for Range.Offset() http://msdn.microsoft.com/en-us/library/office/ff840060%28v=office.15%29.aspx
However you could do it as:
'Your example Range(Col_B_in_current_row) as
Range("B" & ActiveCell.Row).Select
'Your example Range("B2:B10") -> Range("valuesabove") as
Range("B2:B10").Offset(-1, 0).Select
Just seems like a relatively simple syntax already exists for this.
I think I've found a proper and compact solution. It's
Names("mixedname").RefersToRange
Not as short as Range("mixedname") would be but it is really providing the expected values.
UPDATE:
This solution is mostly unuseful if you want to copy relative-named cell values in a source workbook to relative-named cells in a dest workbook with a single codeline. This is because Names() relies on the actual position of the cursor which is depending on which workbook is currently the active one and in most cases this won't be ok for the other.
In this case the non-fixed part of the name has to be stored:
sourcerow = ActiveCell.Row
[...]
'opening a wbk, this also makes it the active one
[...]
Names("dest").RefersToRange = mysheet.Cells(sourcerow, mybook.Names("src").RefersToRange.Column)
To reference a Range relative to another Range you can use this syntax:
myRange.Range("namedRange")
Note: This only works if both the Row offset AND the Column offsets are positive. For example if the "Refers to" formula for the named range is "=Offset(A1,r,c)", then the above syntax will throw an error if Either r Or c is negative. But, it will work if both are positive.
The asymmetry is unfortunate but business as usual for VBA...
To Reference the third column in the row of the current ActiveCell:
ActiveCell.EntireRow.Range("C1")
To reference a cell offset by (for example) 1 row and 3 columns relative to the ActiveCell:
ActiveCell.Range("C2")
Obviously, you can use the same syntax with the Selection Object or any other Range value in VBA.
Private Sub Worksheet_Change(ByVal Target as Range)
If Not Intersect(Target.Address,ThisWorkbook.Sheets('sheetname).Range('RangeName)) Is Nothing Then _
'Do whatever you want down here.
ThisWorbook.Sheets('sheetname).Range('RangeName).Offset(0,Target.Row)
End If
End Sub
This should send you on the right path to what you want (which is super unclear). Use the worksheet change event to bring in user worksheet selections and changes into VBA modules. Put it into the relevant sheet.
I had the same problem, but I did get it to work - sort of. I don't know what is different about the simple example below, but it works. At first I thought selection mattered, but no - it works without changing the active cell.
(I still can't get it to work in my main spreadsheet.)
Named range: "TestName" = Sheet1!$H1
Values in H1:H10 = 1,2,3,4,5,6,7,8,9,10
Sub Test()
Dim x As Integer
For x = 0 To 10
Range("A1").Offset(x, 0).Value = Range("A1").Offset(x, 0).Range("Testname").Value
Next x
End Sub
Result: A1:A10 = 1,2,3,4,5,6,7,8,9,10

how to write an IF formula in excel or spreadsheets if you want to check for links

I was wondering if it was possible to write an IF formula in excel or sheets that would check if the cell contained a link. Currently there are rows of data that strings and some data that have web addresses.
Is it possible to write if formula for this?
Thanks
If you want to use just off-the-shelf available Excel functions you could us "=Find()" or "=Search()" to test if a cell had any of the common elements of a web address, e.g. "www." or ".com" etc. You might have to nest a few "=IFERROR()" statements or use "=IFERROR(OR(),,)" to cover the possibilities.
You would want to use "=IFERROR()" to trap out errors for the cells that don't have any common web address elements.
So, it might look like "=IFERROR(FIND("www",A1)>0,0)" this would return a "TRUE" if it found "www" and a "0" if it didn't and you could nest that in another "=IF()" statement.
It's not bullet proof but it might be sufficient.
I don't know of an Excel function that specifically tests for a hyperlink in a cell.
Not sure about using a formula, but you can do this easily with VBA if you feel so inclined:
If Range("A1").Hyperlinks.Count > 0 Then
MsgBox "A hyperlink"
Else
MsgBox "NOT a hyperlink"
End If
The above checks if cell A1 contains a hyperlink or not. It's simplistic, but hopefully you get the idea.
If you are using VBA you could write your own user defined function which could then be used in an if statement.
Function ishyperlink(r As Range) As Boolean
If r.Hyperlinks.Count > 0 Then
ishyperlink = True
Else
ishyperlink = False
End If
End Function
in the cell =if(ishyperlink(A1),"hyper","no hyper")

When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?

I have this VBA function:
Public Function testPrec(target As Range) As String
testPrec = target.Precedents.Address(External:=False)
End Function
In cell C11, I have this formula:
=C6+C8
If I call testPrec from the immediate window, it works just fine:
?testPrec([c11])
$C$6,$C$8
EDIT: It also works fine if called from a non-UDF macro Sub. The anomaly is the UDF case.
If I call it from the worksheet as a UDF:
=testPrec(C11)
I just get back "$C$11".
Does anyone know what's going on, or even better how to get the actual precedents from within a UDF call? (I'm using Excel 2007.)
It seems the constraint lies in that any call to .Precedents in a call stack that includes a UDF gets handled differntly. So, find a way to do the call outside the call stack triggered from the UDF: One thought is to use events. Here is a overly simplistic example to demonstrate
In a module define
Public strPrecedent As String
Public rngPrecedent As Range
Public Function testPrec(target As Range) As String
Set rngPrecedent = target
testPrec = strPrecedent
End Function
In a sheet define
Private Sub Worksheet_Calculate()
If Not Module1.rngPrecedent Is Nothing Then
Module1.strPrecedent = Module1.rngPrecedent.Precedents.Address(External:=False)
End If
End Sub
testPrec now returns the correct range address, albeit one recal late. The idea is to have the UDF build a list of addresses to get Precedents for, and an event to do the actual GetPrecedent work, returning the address strings to the list for pickup by the udf. You might be able to build a workable solution out of this, depending on your needs.
The only workaround I can think of is to get target.formula and parse it - not very nice.
I ran into a similar problem: I had to format cells based on whether they contain a formula or a constant value. HasFormula makes it possible to determine if a cell contains a formula, however, simple calculations, like =123+45 are also detected as formulas (correctly from a technical point of view but incorrectly from a financial modelling perspective). So I wanted to use Precedents in a UDF to see whether the given cell links to any other. As mentioned above the value of Precedents during the execution of an UDF is not valid but I needed to know only if there is any precedent, not which cells they are.
So I compared the Formula and FormulaR1C1 properties because they are different only in case the Formula contains a cell reference.
There is one exception: If the Formula contains Named Ranges, then Formula and FormulaR1C1 can be equal even though the cell refers to something. (This was not relevant in my case and did not want to iterate all Names and check if they are contained in the Formula outside quotation marks.

Resources