I'm having a problem while passing ranges across two subprocedures. Can you suggest the possible error ?
I have defined two subprocedures in VBA. In the first subprocedure, I have a selection of cells (3X3 MATRIX), named under "ABC" which I'm copying to another selection of cells "PQR". This is working :)
I wanted to enable "all borders" when the values are copied on PQR from ABC. For this I recorded a macro.
But, whenever I run this subprocedure, it is giving an error that object doesn't exist.
I called the macro in the following manner :
All_border_test PQR
The code for subprocedure is as given below :
Sub All_borders_test(d As Range)
Range(d).Select
' Recorded Macro to enable all borders (its working)
End Sub()
1- Take a look at: What's the RIGHT way to reference named cells in Excel 2013 VBA? (I know I'm messing this up) and VBA Reference Named Range ActiveSheet
2- fix your code to be like:
Sub All_borders_test(d As Range)
d.Select ' old code was: Range(d).Select
End Sub 'no parenthesis here
3- you can call All_borders_test using one of the following calls:
Call All_borders_test([PQR])
Call All_borders_test(Range("PQR"))
Call All_borders_test(Sheet1.Range("PQR")) ' assuming that PQR range exists in Sheet1
Related
I'm using a userform to collect data and add it to an empty line in a workbook.
Structure of code is as follows:
Main sub s_OpenWriteToTargetFile is called from userform mainForm.
It checks availability of the target workbook.
It opens the target workbook.
It calls sub "s_WriteLines". Everything is OK up to this point.
Sub s_WriteLines should load textbox values from mainForm into various variables and paste them into the target workbook.
For some reason, code execution jumps out of s_WriteLines as soon as it reaches With MainForm..., and it returns to the mother sub.
s_WriteLines sub
Sub s_WriteLines
Dim a,b as integer
With mainForm
a = .tb_a.Value
b = .tb_b.Value
End With
End Sub
I can't wrap my head around it. Does this have something to do with the modality of the userform?
As AcsErno suggested in the comments, there was a on error resume next that I didn't notice, and it kept me from learning that the form is failing to load a rowsource property of a combobox.
The rowsource was specified as follows:
mainForm.cb_Wiresize.RowSource = wiresizesWSheet.Name & "!" & wiresizesFinalRange.Address
The workbook that is opened to be written in also becomes active, and then the range that I specified as rowsource refers to a worksheet that doesn't exist - because I specified it only as "worksheet + range", instead of "workbook + worksheet + range".
To expand on my question, how can I refer to the specific workbook object using the syntax posted above? I tried different formulations but none worked.
I have cell A1 on a sheet named "Data" that looks for input which when received, looks for a sheet name that matches it. If it finds a match, it opens that sheet. I'm trying to clear the value entered in A1 of "Data" after that second sheet has been opened however I'm getting a runtime error that appears to still be looking for the data used to open the second sheet. Here is the code for the "Data" sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Range("A1"), Target) Is Nothing Then Exit Sub
Sheets(Target.Value).Activate
End Sub
I tried using a variable in place of Target.Value hoping that after deleting the actual data in A1, the variable would satisfy the code.
I've ran the following line on at the end of the block above as well as on the sheet which gets activated but either way I get an error.
Sheets("Data").Range("A1:A1").ClearContents
The error is "Run-time error 9 Subscript out of range.
How do I clear the contents of A1 on "Data" so it's ready to receive another request to open another sheet when I'm done with the last one?
This is the correct syntax for a single cell:
Sheets("Data").Range("A1").ClearContents
...however using a range of A1:A1 should also work, so if you're getting Subscript Out Of Range then there is likely no worksheet named Data.
If you have multiple workbooks open then by default, it's looking for the Active Workbook (whose name in contained in ActiveWorkbook.Name.) So if you're going to be working with multiple workbooks, you should explicitly state the workbook name as well:
Workbooks("Book1").Sheets("Sheet1").Range("A1").ClearContents
I didn't need to clear the value after all. I added a couple lines to ensure when returning to the "Data" sheet, cell A1 was selected. This allows for a new value to be entered replacing the previous value and serves the purpose.
Just a slight change to your code. "Is Nothing" does not work. The below code works fine for me.
If Intersect(Target, Range("A1")) = "" Then Exit Sub
Sheets(Target.Value).Activate
Target.ClearContents
I have inherited an Excel workbook with several worksheets, all with named tabs. I have some VBA code that runs depending on buttons and inputs. When I compare the VBAProject and the list of Excel Objects, the sheet's names match the tabs. All good so far.
However, within the VBA code and on the spreadsheets itself, it refers to other worksheets. They are still part of the workbook, and I think that the code was created, and then tabs were renamed. But I don't know how Excel keeps the connection, or, more importantly, how I am supposed to figure out the connections.
So, for instance, I have a VLOOKUP that refers to MiscDataRange
=IF((VLOOKUP(E4,MiscDataRange,4,0))="Y"...
I don't know what MiscDataRange is, but within the VBA code I find one reference. Right after specifying worksheet "Misc Interrupt", which is NOT any of the named tabs.
Worksheets("Misc Interrupt").Range("H2:H47") = "N" 'Reset to N at noon.
UpdateData
Range("MiscDataRange").ClearContents
I do have a sheet called MiscInt, and it appears to be the sheet that "Misc Interrupt" is using and MiscDataRange is referencing.
My problem is there is a hole in my knowledge - I can guess that MiscInt and Misc Interrupt are the same worksheet, that the VLookup is referring to data on the MiscInt sheet. But I am reduced to guessing. I cannot find anything in the file that maps those two as the same. Where would I look to find that?
This question seems related, except he simply has a VLookup, and isn't looking at the VBA code: Non-existent Excel Worksheet, but Formulas and Defined names still work?. In addition, from the VBA code, I can see hidden and visible worksheets.
You can open the Names manager by going to the Formula Tab and clicking Names Manager or pressing ctrl+F3 or you can paste a list of Names and what the names reference by pressing F3. It may be necessary to unhide the names first.
Sub ShowAllNames()
Dim n As Name
For Each n In ThisWorkbook.Names
n.Visible = True
Next
End Sub
If I understand your question, you're looking to find where those named ranges are.
You can use a sub like this:
Sub t()
Debug.Print "Sheet: " & Range("testNamedRange").Parent.Name
Debug.Print "Full Location: " & Range("testnamedrange").Name
Debug.Print "File path: " & Range("testnamedrange").Worksheet.Parent.Path
End Sub
Does that help?
I want to make a macro that copies data from one sheet to another.
No problem, but I named the sheet with an emoji.
How can I tell VBA which sheet he has to use if the name of the sheet is for example: 🏠
Thanks in advance
You can use the AscW function to find the appropriate unicode value for the item and use that to find the correct sheet
To find the name of any given worksheet, activate the worksheet, open the VBA Editor (Alt+F11), open the Immediate Window (Ctrl+G) and type the following:
? ActiveSheet.Name
If the name for some reason is nonsensical, and only consists of a single character, run ? Asc(ActiveSheet.Name) to get the ASCII value.
Referencing an ASCII value in VBA can be done by calling Chr(putValueHere), for example like this:
Worksheets(1).Name = Chr(50)
If you have a plethora of sheets, you can print all of them by running this code:
Sub SheetNamePrinter
For i = 1 To Worksheets.Count
Debug.Print Worksheets(i).Name
Next i
End Sub
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.