What I want to do is select a range B2:B5and give it a name, just above cells A1 and B1 there is a namebox and I type the name: "My_Test_Range" here and hit enter.
The word Range is this the official name for range as described above in Excel?
Then I want to loop trough the range B2:B5 using VBA and do something like make all the cells to the right of the ranged cells 1.
How do I do the above?
I want to do this with the named range, because I find a name like "Options_For_Red_Car" or "Options_For_Blue_Car" much easier to read than B2:B5 etc., especially if you get say a dozen such ranges.
Range is a very important object in the Excel object model. Here is one of probably thousands of references to information about ranges:
http://msdn.microsoft.com/en-us/library/office/ff838238(v=office.15).aspx
Seems like you like named-ranges which is good as they are very powerful and useful and if you're going to start playing with vba then you'll find them more and more useful.
To loop through the cells in a range you can do something like the following:
Sub loopThroughRangeCells()
Dim cell
For Each cell In Excel.ThisWorkbook.Sheets("Sheet1").Range("A2:C6").Cells
MsgBox cell.Address
Next
End Sub
Although really it is better to create object reference variables when doing something like the above and also to use a `named-range':
Sub loopThroughRangeCells()
Dim cell
Dim s As Excel.Worksheet '<<creates an object variable
Set s = Excel.ThisWorkbook.Sheets("Sheet1") '<<the object variable now references our target sheet
'<<using object variable and named range the following code is simplified
For Each cell In s.Range("helloWorld").Cells
MsgBox cell.Address
Next
End Sub
In the above I've just done MsgBox cell.Address within the loop but you can change this to anything you like - you might like to experiment and try to change the cells to the right to 1.
In the above I've declared a variant typed variable cell. This is standard practice to call each member of the collection cells a cell even though no object cell exists in the object model. This is different than most collection like worksheets where it is a collection of an intuitive object worksheet
Related
I have a named range in Excel that I am trying to clear using VBA.
The problem with the range is that spans across multiple sheets and I am not sure how to properly reference the named range in VBA since it covers multiple sheets.
The Named Range "Counts" is set to Workbook scope with the following cell references:
=Sheet1!$A$1, Sheet2!$A$1, Sheet3!$A$1
When clearing a named range where it only has cells referenced on one sheet I use the following:
ThisWorkbook.Sheets("Sheet1").Range("Counts").ClearContents
I have tried the following but neither seemed to work.
ThisWorkbook.Range("Counts").ClearContents
and
Range("Counts").ClearContents
The last gives me a global error.
Instead of a range that goes across multiple sheets (which does not work, as we have established), you need a worksheet scoped range in each sheet.
When defining a range name you can set its scope to workbook or the current sheet. This way you can have the same range name in many sheets.
Use VBA to loop through all worksheet, access the ws.Range("TheRangeName") on the current sheet and clear its contents.
That's a cleaner approach.
I would write something that displays the names and you can use that to remove it...
In the immediate window:
For i = 1 to names.count:Debug.print i, Names(i).RefersTo, Names(i).name:next
You can then either use th name or the index to remove the particular name you want.
Hope that helps.
Rory Archibald states on his website post about named ranges that: A Range object can only refer to cells on one worksheet. You cannot refer to cells on different sheets with one Range object.
So I am unable to accomplish what I was wanting but I should be able to just create multiple named ranges and just clear them one at a time.
I was able to complete the code for this as follows with inspiration from teylyn
Public Sub ClearRanges()
'Checks if named Range exists on sheet if it does then clear contents
Dim ws As Worksheet
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If Len(ws.Range("Counts").Name) <> 0 Then
ws.Range("Counts").ClearContents
End If
Next ws
Application.DisplayAlerts = True
End Sub
As the question says, how to create an empty range variable object:
tested with the code below it cannot insert a new cell/range from a different source (workbook/worksheet).
Public Sub test()
Dim Sheet As Worksheet
Dim t As Range
Set Sheet = ActiveWorkbook.Sheets(1)
Sheet.Activate
Set t = Sheet.Range("A1:A1")
t.Delete
t.Insert
End Sub
the above code gives me the object required exception. How do we create an empty Range and populate it with cells from another source or at least a custom made cell to be inserted in the Range?
similar to how an array object is capable or in a gridview where we can create a row/column/cell object instantiate it and give values to it and add it to gridview, like how you do it in asp.net/c# winforms?
After you have deleted a Range you cannot refer to it because it does not exist. The address A1 of course still exists but now points to a different range.
You can clear a range or overwrite it with new data or copy a range from somewhere and paste it somewhere else.
BTW inserting ranges can be very time-expensive ...
I'm new to VBA. I'm attempting to create over 500 xlClusteredColumn charts using two columns of information and I'd like to expedite the work. The first column contains names I'd like to use for named ranges (i.e.: Line1, Line2, etc.) and the second column contains the indirect references of the data ranges (i.e., Sheet1!C4:D28, Sheet1!C28:D90). I noticed that if I use a named range for the "Chart Data Series" field, the data shows up nicely (but I have to first create that named range being sure to include the INDIRECT formula in the reference, (e.g.: Named Range Line1 is equal to =INDIRECT(Sheet1!C4:C28)). The ranges will be static.
In reviewing prior questions I couldn't seem to find a solution that would select the first cell in this set and name it, then uses the second cell to define that range. I think I might need the ActiveWorkbook.Names.Add Name:= formula and combine it with a loop (but I couldn't get it to use a selection or cell to define the Add Name aspect, only a hard coded name).
If the solution requires it, I can go back and extract the individual ranges (i.e.: C4:D28) from the cell and have the chart reference only that if it makes the code simpler. I know my first outlined attempt isn't the only solution and there's probably one much more elegant. I figured using named ranges would speed up the chart work, but perhaps there's a way to cut that step out?
Populating a new sheet with all the charts for each of these ranges would be icing on the cake, but I'll be happy enough receiving help to get the data set up to chart.
Example information:
NameRange1 (let's say in cells A1:A4)
WKD_1_NB
WKD_2_EB
WKD_3_EB
SerRange1 (in cells B1:B4)
WKDpivot!C4:D43
WKDpivot!C84:D140
WKDpivot!C197:D233
(Chart data range requires the reference of named range "WKD_1_NB" to be '=INDIRECT(WKDpivot!C4:D43)' in order for the chart to work.
OK so why don't you try the two-step process. I am going to do this without Indirect because I don't see that it is necessary.
Sub CreateNames()
Dim rng As Range
Dim r As Range
Dim myName As String
Dim addr As String
Set rng = Range("A1:A2") '## Modify as needed
For Each r In rng.Cells
myName = r.Value
addr = "=" & r.Offset(0, 1).Value
ThisWorkbook.Names.Add myName, addr
Next
End Sub
This creates your names (screenshot). Note there are some rules about naming conventions and allowable names, etc., the code above does not take any of these in to account.
From there it should be fairly simple to create a loop that adds your charts one by one, and assigns each named range to each chart.
The Problem
Assume that the active cell contains a formula based on the INDEX function:
=INDEX(myrange, x,y)
I would like to build a macro that locates the value found value by INDEX and moves the focus there, that is a macro changing the active cell to:
Range("myrange").Cells(x,y)
Doing the job without macros (slow but it works)
Apart from trivially moving the selection to myrange and manually counting x rows y and columns, one can:
Copy and paste the formula in another cell as follows:
=CELL("address", INDEX(myrange, x,y))
(that shows the address of the cell matched by INDEX).
Copy the result of the formula above.
Hit F5, Ctrl-V, Enter (paste the copied address in the GoTo dialog).
You are now located on the very cell found by the INDEX function.
Now the challenge is to automate these steps (or similar ones) with a macro.
Tentative macros (not working)
Tentative 1
WorksheetFunction.CELL("address", ActiveCell.Formula)
It doesn't work since CELL for some reason is not part of the members of WorksheetFunction.
Tentative 2
This method involves parsing the INDEX-formula.
Sub GoToIndex()
Dim form As String, rng As String, row As String, col As String
form = ActiveCell.Formula
form = Split(form, "(")(1)
rng = Split(form, ",")(0)
row = Split(form, ",")(1)
col = Split(Split(form, ",")(2), ")")(0)
Range(rng).Cells(row, CInt(col)).Select
End Sub
This method actually works, but only for a simple case, where the main INDEX-formula has no nested subformulas.
Note
Obviously in a real case myrange, x and ycan be both simple values, such as =INDEX(A1:D10, 1,1), or values returned from complex expressions. Typically x, y are the results of a MATCH function.
EDIT
It was discovered that some solutions do not work when myrange is located on a sheet different from that hosting =INDEX(myrange ...).
They are common practice in financial reporting, where some sheets have the main statements whose entries are recalled from others via an INDEX+MATCH formula.
Unfortunately it is just when the found value is located on a "far" report out of sight that you need more the jump-to-the-cell function.
The task could be done in one line much simpler than any other method:
Sub GoToIndex()
Application.Evaluate(ActiveCell.Formula).Select
End Sub
Application.Evaluate(ActiveCell.Formula) returns a range object from which the CELL function gets properties when called from sheets.
EDIT
For navigating from another sheet you should first activate the target sheet:
Option Explicit
Sub GoToIndex()
Dim r As Range
Set r = Application.Evaluate(ActiveCell.Formula)
r.Worksheet.Activate
r.Select
End Sub
Add error handling for a general case:
Option Explicit
Sub GoToIndex()
Dim r As Range
On Error Resume Next ' errors off
Set r = Application.Evaluate(ActiveCell.Formula) ' will work only if the result is a range
On Error GoTo 0 ' errors on
If Not (r Is Nothing) Then
r.Worksheet.Activate
r.Select
End If
End Sub
There are several approaches to select the cell that a formula refers to...
Assume the active cell contains: =INDEX(myrange,x,y).
From the Worksheet, you could try any of these:
Copy the formula from the formula bar and paste into the name box (to the left of the formula bar)
Define the formula as a name, say A. Then type A into the Goto box or (name box)
Insert hyperlink > Existing File or Web page > Address: #INDEX(myrange,x,y)
Adapt the formula to make it a hyperlink: =HYPERLINK("#INDEX(myrange,x,y)")
Or from the VBA editor, either of these should do the trick:
Application.Goto Activecell.FormulaR1C1
Range(Activecell.Formula).Select
Additional Note:
If the cell contains a formula that refers to relative references such as =INDEX(A:A,ROW(),1) the last of these would need some tweaking. (Also see: Excel Evaluate formula error). To allow for this you could try:
Range(Evaluate("cell(""address""," & Mid(ActiveCell.Formula, 2) & ")")).Select
This problem doesn't seem to occur with R1C1 references used in Application.Goto or:
ThisWorkbook.FollowHyperlink "#" & mid(ActiveCell.FormulaR1C1,2)
You could use the MATCH() worksheet function or the VBA FIND() method.
EDIT#1
As you correctly pointed out, INDEX will return a value that may appear many times within the range, but INDEX will always return a value from some fixed spot, say
=INDEX(A1:K100,3,7)
will always give the value in cell G3 so the address is "builtin" to the formula
If, however, we have something like:
=INDEX(A1:K100,Z100,Z101)
Then we would require a macro to parse the formula and evaluate the arguments.
Both #lori_m and #V.B. gave brilliant solutions in their own way almost in parallel.
Very difficult for me to choose the closing answer, but V.B. even created Dropbox test file, so...
Here I just steal the best from parts from them.
'Move to cell found by Index()
Sub GoToIndex()
On Error GoTo ErrorHandler
Application.Goto ActiveCell.FormulaR1C1 ' will work only if the result is a range
Exit Sub
ErrorHandler:
MsgBox ("Active cell does not evaluate to a range")
End Sub
I associated this "jump" macro with CTRL-j and it works like a charm.
If you use balance sheet like worksheets (where INDEX-formulas, selecting entries from other sheets, are very common), I really suggest you to try it.
I'm having troubling referring to a Dynamic Name Range in VBA.
My ranges are defined as
=OFFSET(Sheet!$B$2,0,0,COUNTA(Sheet!$B:$B)-1,1)
My code should search one range for all entries in another range, the intention being that any missing entries will be added. So far I have
Sub UpdateSummary()
Dim Cell As Range
Dim rngF As Range
Set rngF = Nothing
' Step through each cell in data range
For Each Cell In Worksheets("Aspect").Range("A_Date")
' search Summary range for current cell value
Set rngF = Worksheets("Summary").Range("Sum_Date").Find(Cell.Value) // Does not work
If rngF Is Nothing Then
' Add date to Summary
End If
Set rngF = Nothing
Next Cell
End Sub
The For loop seems to work ok. However, using the .Find method is giving me an error message.
Application-defined or object-defined error
It does work if I replace the named range with a specific range ($B$2:$B$5000), so it seems to be down to how the named range is being passed.
Any ideas would be appreciated.
Thanks.
The error is almost definitely because Excel can't find a named range Sum_Date that refers to a range on a worksheet named Summary. The most common causes are
Sum_Date refers to a sheet other than Summary. Check the RefersTo property of Sum_Date and make sure nothing is misspelled.
There is not a named range Sum_Date, that is, it's misspelled in the VBA code. Check the spelling of the named range in the Name Manager.
There is an error in the RefersTo formula of Sum_Date. It sounds like you already verified that this isn't the case.
I've had the a similar if not the same problem & here's how I solved it:
I first realized that the method I used to create my named range, using the Name Manager, my named range had a scope of Workbook. This is important because, it doesn't belong to the worksheet, & therefore will not be found there.
So, Worksheets("Summary").Range("Sum_Date") would not work for me.
Since my range belonged to the workbook, the way I was able to find is to use ActiveWorkbook.Names("Sum_Date")
For me I used it to remove the formula from named range that I am using in many places. The huge advantage is that named range is updated only once instead of the formula being called for every cell location that ranged is called. Huge time delay difference!
Public last_Selection As String
Private Sub Worksheet_Change(ByVal Target As Range)
'excel data change detection
If Range(last_Selection).Column = 2 Then
'Disable events, so this only executes once
Application.EnableEvents = False
'This can be done with a complex formula in a cell,
'but this is easily understood
Range("B1").End(xlDown).Select
ActiveWorkbook.Names("last_Entry").Value = ActiveCell.Row
'Re-enable so this routine will execute on the next change
Application.EnableEvents = True
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'constantly store the last cell to know which one was previously edited
last_Selection = Target.Address
End Sub
I know this is a very old thread, but I had the same issue today and I was looking for solution for quite a long time. So maybe this will help someone.
The named "range" defined by the =OFFSET(...) formula is actually a named FORMULA, so in VBA you have to evaluate it first to get the range. E.g.:
Set rgNamedRange = Worksheets("Summary").Evaluate("Sum_Date")
Credits to a guy named "shg" from mrexcel.com, who got me on right track. :)
I have been experimenting with this for a few days and eventually I came up with the following. It may not be the most efficient but it did work for me!
The named range of "OhDear" was set up in the normal way
Dim vItem As Variant
Set vItem = Names("OhDear")
Debug.Print vItem.Name
Worth a try don't you think!
This does not work if instead of using a variant you use something like: Dim Nm as Name: Set Nm = Names("OhDear"). Any variations using 'Nm' failed!!!