I'm trying to use visual basic for applications to loop through a list of named ranges from an excel sheet as the first step in a process for altering their formulas. Its all part of an Excel plug in I work with using Visual Studo I have a basic loop, which came directly from the MS docs.
Dim n As Excel.Name
Dim names As Excel.Names = destStreetEstimates.Names
Dim test_string As String = destStreetEstimates.Name
MsgBox(test_string)
For Each n In names
MsgBox(Prompt:=n.Name)
Next n
This doesn't work, it looks like com objects are being put together into a list when I turn on the VS debugger (yay), but the com objects aren't being turned into anything useful I can loop through. (boo).
Am I missing something? I've gone through the Docs several times, nothing I've read there matches with the errors I'm getting. But I'm still pretty green.
https://learn.microsoft.com/en-us/office/vba/excel/concepts/cells-and-ranges/refer-to-named-ranges
I've looked at other guides, most of them seemed to be discussing how to programmatically generate named ranges. I have to start with the ranges I've been given, its about 70, and while I have all their names in a config file there's a good chance the sheet will have additional names I haven't been given in the future and my function has to work in that case too.
See https://www.thespreadsheetguru.com/blog/the-vba-guide-to-named-ranges
Sub NamedRange_Loop()
'PURPOSE: Named Ranges in the Active Workbook
'SOURCE: www.TheSpreadsheetGuru.com
Dim nm As Name
'Loop through each named range in workbook
For Each nm In ActiveWorkbook.Names
Debug.Print nm.Name, nm.RefersTo
Next nm
'Loop through each named range scoped to a specific worksheet
For Each nm In Worksheets("Sheet1").Names
Debug.Print nm.Name, nm.RefersTo
Next nm
End Sub
Related
The code is:
Sub Copy_Filtered_Table()
Dim aSheet As Worksheet
Dim i As Long
i = ActiveSheet.Index
ActiveSheet.AutoFilter.Range.Copy
-> Set aSheet = ActiveWorkbook.Worksheets.Add(After:=i)
aSheet.Range("A1").PasteSpecial
End Sub
The workbook format is .xlsm Excel 2016
it has sheets after and before the active sheet
Also I Have tried doing it with out the aSheet variable like this
ActiveWorkbook.Worksheets.Add After:=i
It did not work too. both cases gives error 1004 Method 'Add' of object 'Sheet' faild.
If I ommited the After parameter it works but putting the result new sheet before the active sheet which exactly I am avoiding.
In order to insert relative to an existing sheet, you need to provide the actual sheet rather than its index, using one of:
Set aSheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(i))
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Worksheets(i)
Which one you choose depends on whether you immediately want to do something with the sheet without searching for it again but I suspect you already know that, given your question.
As an aside (though I haven't tried), I suspect getting the index of the current sheets then turning that back into the current sheet object is a bit unnecessary. You may want to just try:
Set aSheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.ActiveSheet)
My code where I copy from one worksheet to another doesn't appear to be working.
I have tried messing around with the ranges but it didn't seem to work.
Workbooks("Copy of Sales Report_063019(002).xlsx").Worksheets("EBR
RANKING").Range("A1:O134").Copy _
Workbooks("Copy of
ProspectAndSalesReportAll_123118_FINAL(2).xlsm").Worksheets("EBR
Ranking").Range("A1")
A lot of subscript out of range errors.
This is not a complete answer, but you'll typically avoid these kinds of errors if you break out each object into an intermediate variable. You're not gaining anything at all by "stacking" all of the references into one long line. In fact, you're forcing Excel to (re-)evaluate it each and every time. The bonus is that your code becomes much clearer.
As an example:
Dim firstSalesWB As Workbook
Dim firstSalesWS As Worksheet
Dim firstSalesData As Range
Set firstSalesWB = Application.Workbooks("Copy of Sales Report_063019(002).xlsx")
Set firstSalesWS = firstSalesWB.Sheets("EBR Ranking")
Set firstSalesData = firstSalesWS.Range("A1:O134")
Dim allSalesWB As Workbook
Dim allSalesWS As Worksheet
Dim allSalesData As Range
Set allSalesWB = Application.Workbooks("Copy of ProspectAndSalesReportAll_123118_FINAL(2).xlsm")
Set allSalesWS = allSalesWB.Sheets("EBR Ranking")
Set allSalesData = allSalesWS.Range("A1")
firstSalesData.Copy Destination:=allSalesData
Now when you get those kinds of errors, it's much easier to track down what the problem is -- in your case it's probably either a missing or mis-spelled workbook name or worksheet name as #BigBen mentioned.
1)do you have both worksheets open? If not, you should open both, or if you don't want to do that, you'll need to put the full filepath so that VBA knows were to find the files.
2) you mention copying the worksheet, but what your code is doing is copying the contents of a sheet to another. Does the EBR Ranking sheet exist in the other sheet? If not, here is a snippet to add one.
With Workbooks("Copy of ProspectAndSalesReportAll_123118_FINAL(2).xlsm")
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = "EBR Ranking"
End With
I'm working on a spreadsheet that breaks out the tasks in a given department. Each task is then assigned to a person in that department using a data validation drop down that dynamically fetches values from the tables that list each employee/role in the department. The tables are on a different sheet than the task breakdown.
Each individual needs their own background color that automatically fills in when their name is selected from the drop down on the tasks sheet. What I'm hoping to do is write a macro that looks for that person's name in the table (note that I'm using named ranges) and then matches the formatting of the selected cell to their row in the table. I'm a super beginner with VBA and have hit the end of my abilities. Several answers that come close to what I want to do, but in terms of adapting it for my specific use case, I'm stuck.
I grabbed code from this thread, which is essentially the result I want to achieve, except that their key is on the same sheet and mine can't be: https://superuser.com/questions/472918/excel-conditionally-format-a-cell-using-the-format-of-another-content-matching
So far, I've compiled this:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If VarType(Target) > vbArray Then Exit Sub
' if multiple cells are changed at once, then exit
Dim kr1 As Range
Dim kr2 As Range
Dim KeyRange As Range
Dim TargetRange As Range
Dim lCell As Object
Dim kCell As Object
Set kr1 = Application.Range("ESFormattingRange")
Set kr2 = Application.Range("CSFormattingRange")
Set KeyRange = Application.Union(Range("kr1"), Range("kr2"))
' formatting key is here
Set TargetRange = ThisWorkbook.Worksheet("Sheet3").Range("A:X")
' changing cells in this area
For Each kCell In KeyRange.Cells
If kCell.Value <> "" Then
For Each lCell In TargetRange.Cells
If lCell.Value = kCell.Value Then
' only change cells that match the edited cell
lCell.Font.Color = kCell.Font.Color
lCell.Interior.Color = kCell.Interior.Color
' copy whatever you feel needs to be copied
End If
Next
End If
Next
End Sub
When I run this, I get the following method error, but no lines are highlighted when I try to debug:
Compile error:
Method or data member not found
I'm thinking maybe there's something wrong with the way I've constructed my range variables, but I've googled everything I can think of and I'm at a loss.
Any help is greatly appreciated!
The VBE should be highlighting the word Worksheet in ThisWorkbook.Worksheet("Sheet3").Range("A:X").
"Method or data member not found" means Worksheet isn't a member of ThisWorkbook.
You can fix this by pressing CTRL+SPACE to autocomplete the member name to Worksheets.
Alternatively, you can re-type the . dereferencing operator after ThisWorkbook, and press TAB when the names list dropdown is shown, highlighting the Worksheets member - that will also autocomplete the member name to Worksheets.
Rule of thumb, if you type a . dereferencing operator and then type something that isn't in the names list, you can expect this compile error.
When you make this typo against a Variant or Object variable, the code will happily compile, but error 438 will be thrown at run-time - like this:
ThisWorkbook.Worksheets("Sheet3").Ragne("A:X") ' <~ typo compiles. Option Explicit can't save you.
The reason is that Worksheets returns an Object reference, so any member calls chained to it are resolved at run-time. A safer way to code is to declare a local Worksheet variable to hold this object, and then work with that object instead:
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("Sheet3")
sourceSheet.Rnage("A:X") ' <~ typo throws at compile-time now!
If the worksheet object exists in ThisWorkbook at compile-time however, then it's probably a better idea to work with its code name instead. Locate Sheet3 in the Project Explorer (CTRL+R), then find its (Name) property - change it to e.g. SourceSheet. And then you can do this:
SourceSheet.Range("A:X") ' <~ a typo wouldn't compile here.
...without needing to explicitly declare a SourceSheet.
I have a worksheet that often needs to be printed in a specific order of worksheets and ranges. What I'm trying to do is
Print out specific worksheets and ranges in order to a single PDF file.
Save the PDF file as a specific date to a certain folder.
The obstacle I'm running into is getting the numerous sheets and ranges printed into one PDF file, as currently each worksheet or range prints out to its own single PDF file.
I'm assuming there's a way to put all the necessary sheets and ranges in something like an array and then do a .PrintOut to that variable, however I haven't gotten this to work.
I'm using Excel 2010 and so I just use the "Adobe PDF" Printer.
How can I print multiple ranges and worksheets to a single .pdf?
To print more than one worksheet, you can put the worksheet names in an array like this
Sub PrintArrayOfWorksheets()
Dim vaWorksheets As Variant
vaWorksheets = Array("Sheet1", "Sheet2", "Sheet3")
ThisWorkbook.Worksheets(vaWorksheets).PrintOut
End Sub
Printing to PDF has special problems. If you're using the "official" add-in for creating PDFs it will probably work as above (sorry I can't try it right now). In the past when I've worked with other printer drivers that print to PDF, I found that all (or at least most) of the PageSetup properties had to be identical on the sheets or it would print in multiple jobs. That means no shrink-to-fit and all the margins have to be the same. I can't remember all the properties that caused problems, just that those two definitely did and Orientation definitely didn't.
To limit the ranges that print, you need to set the print area on each sheet. You can use the PageSetup.PrintArea property to do it in code. But if doesn't change, it's probably just as well to do it manually one time and it will persist.
See code below. This was used to print multiple sheets in a custom order using a VBA Button. It prints to whatever printer is selected prior to clicking the button.
In essence what it does is selects the sheets that you want and rearranges them at the end of the workbook then prints them. after printing it reorders them to the original order.
Option Explicit
Private Sub Print_Sheets_InOrder_Click()
Dim ary
Dim orig() As String
Dim a As Variant, fp As String, i As Variant
ary = Array("Sheet1", "Sheet4", "Sheet3")
fp = ActiveWorkbook.Path
ReDim orig(1 To Sheets.Count)
For i = 1 To Sheets.Count
orig(i) = Sheets(i).Name
Next i
For Each a In ary
Sheets(a).Move after:=Sheets(Sheets.Count)
Next a
ThisWorkbook.Worksheets(ary).PrintOut
For Each a In orig
Sheets(a).Move after:=Sheets(Sheets.Count)
Next a
End Sub
Excel 2010 has a print to pdf feature. If each of your worksheets are set up to print the information that you want, then highlight the various worksheets you want to print to one pdf file, then go to "file" and "save-as" and pick save as type "pdf". It should print the worksheets you have highlighted as you have the print set up for each worksheet.
Here is an approach I have tried ... I print the worksheets to a PS file, then double-click on the PS file to generate a PDF. I know it is a workaround, but printing to PS is lightning quick. It requires you have Adobe Acrobat on your PC.
Dim GetPath, SavePath, ReportSuffix
GetPath = ActiveWorkbook.Path & "\"
ReportSuffix = Range("ReportName").Text & ".ps"
SavePath = GetPath & ReportSuffix
Dim PrintSheets
PrintSheets = Array("Exec1", "Intro1", "Intro2", "Intro3", "Intro4", "Intro5")
Sheets(PrintSheets).PrintOut Copies:=1, PrintTofile:=True, PrToFileName:=SavePath
I'm in the process of refactoring a huge workbook woth a lot of legacy parts, redundant computations, cross-dependencies etc.
Basically, I'm trying to remove unneeded sheets and implement some proper information flow within the workbook. Is there a good way to extract the dependencies between the sheets (with VBA)?
Thanks
Martin
You can use ShowPrecedents and NavigateArrow.
here is some pseudocode
for each oCell in oSht containing a formula
ocell.showprecedents
do until nomoreprecedents
i=i+1
Set oPrec = oCell.NavigateArrow(True, 1, i)
If not oPrec.Parent Is oSht Then
' off-sheet precedent
endif
loop
next ocell
I came up with a little sub to do this. It moves all the sheets into seperate workbooks and prints out the dependencies. The advantage over using showPrecedents is that it captures all links including names, embedded forms/diagramms etc.
Word of warning: Moving worksheets isn't undo-able, save your workbook before running this and close (without saving) and re-open afterwards.
Sub printDependencies()
' Changes workbook structure - save before running this
Dim wbs As VBA.Collection, wb As Workbook, ws As Worksheets
Dim i As Integer, s As String, wc As Integer
Set ws = ThisWorkbook.Worksheets
Set wbs = New VBA.Collection
wbs.Add ThisWorkbook, ThisWorkbook.FullName
For i = ws.Count To 2 Step -1
ws(i).Move
wc = Application.Workbooks.Count
wbs.Add Application.Workbooks(wc), Application.Workbooks(wc).FullName
Next
Dim wb As Workbook
For Each wb In wbs
For Each s In wb.LinkSources(xlExcelLinks)
Debug.Print wb.Worksheets(1).Name & "<-" & wbs(s).Worksheets(1).Name
Next
Next
End Sub
The code isn't very polished or user-friendly, but it works.
You can follow the steps at "Find external references that are used in cells" topic of the following link:
Find external references in a worbook
But instead of enter the "[" you should enter the name of the sheet you're trying to find its dependencies. It will display a large list of every single cell referencing the sheet, but at the end it works. Haven't find the way to group by Sheet.