hi can you help figure out how to copy worksheet if it existing, and if it is not will automatically create a new workbook then save as blank. please see my code below I try it in if the file is existing copy the file and if not create a new blank file.
Workbooks.Open path1
Sheets.Select
If Sheets("Draft") = "" Then
Set wb = Workbooks.Add
ActiveWorkbook.SaveAs saveFolder & "\D201\D201.xlsx", FileFormat:=51
ActiveWorkbook.Close
Else
Sheets("Draft").Copy
ActiveWorkbook.SaveAs saveFolder & "\D201\D201.xlsx", FileFormat:=51
Workbooks(file1).Close
ActiveWorkbook.Close
End If
and I've encountered an error it says Subscript out of range
Pretty sure you didn't try real hard there (given debugging the error thrown would have lead you to the obvious error). 😊
Here are two possible ways to test for the existence of sheet with a specific name:
Sub Temp()
''' Two possible ways to determine if a sheet with a specific name exists
''' Both assume you're looking for the sheet in the Active Book
''' There are other ways
''' Sledge hammer approach (very efficient)
Dim lgErr&
On Error Resume Next: Err.Clear
With Sheets("Draft"): End With: lgErr = Err
On Error GoTo 0
If lgErr <> 0 Then
' Sheets("Draft") does not exist in the active workbook
Else
' Sheets("Draft") does exist in the active workbook
End If
''' More subtle approach (just as effective and only marginally less efficient)
Dim in1%
For in1 = 1 To Sheets.Count
If Sheets(in1).Name = "Draft" Then Exit For
Next in1
If in1 > Sheets.Count Then
' Sheets("Draft") does not exist in the active workbook
Else
' Sheets("Draft") does exist in the active workbook
End If
End Sub
Notes:
The 1st approach if often used by people confident of their vba skills.
The risk is that a coding error between On Error Resume Next and On Error GoTo 0 could result in and invalid conclusion.
The 2nd approach does not have this same risk.
i usually use a function to test if a sheet exists in my workbook:
Function Feuille_Existe(ByVal Nom_Feuille As String) As Boolean
Dim Feuille As Excel.Worksheet
On Error GoTo Feuille_Absente_Error
Set Feuille = ActiveWorkbook.Worksheets(Nom_Feuille)
On Error GoTo 0
Feuille_Existe = True
Exit Function
Feuille_Absente_Error:
Feuille_Existe = False
End Function
Put this on top of your module and when you need it in your code :
If Feuille_Existe("XXX") Then
'do what you want'
End If
Related
I have a macro I cobbled together with my somewhat rudimentary VBA knowledge from a few different sources that's been working for a few years without issue. All of a sudden, it's stopped functioning properly. I haven't made any changes, and I can't determine what the issue is from the error message I get. I'd be very appreciative if someone could take a look and tell me why I'm receiving an error.
I download a report from the web and then open it in Excel. The first time the macro runs it changes the sheet names and then runs some more steps; any additional times, the sheets are already named so it continues on.
This is the beginning of the code; I'll note where I receive the error below. The error code is Run-time error '9': Subscript out of range.
If ActiveSheet.name = "Sheet1" Or ActiveSheet.name = "Sheet2" Or ActiveSheet.name = "Sheet3" Then
Sheets("Sheet3").Activate
Range("A:L").Select
Selection.Delete
Sheets("Sheet1").Activate
ElseIf ActiveSheet.name <> "Sheet1" Or ActiveSheet.name <> "Sheet2" Or ActiveSheet.name <> "Sheet3" Then
ActiveSheet.name = "Sheet1"
Dim xName As String
Dim xSht As Object
On Error Resume Next
xName = "Sheet2"
If xName = "" Then Exit Sub
Set xSht = Sheets(xName) '<--------- Run-time error "9":Subscript out of range
If Not xSht Is Nothing Then
MsgBox "Sheet cannot be created as there is already a worksheet with the same name in this workbook"
Exit Sub
End If
Sheets.Add(, Sheets(Sheets.Count)).name = xName
Dim xName1 As String
Dim xSht1 As Object
On Error Resume Next
xName1 = "Sheet3"
If xName1 = "" Then Exit Sub
Set xSht1 = Sheets(xName1)
If Not xSht1 Is Nothing Then
MsgBox "Sheet cannot be created as there is already a worksheet with the same name in this workbook"
Exit Sub
End If
Sheets.Add(, Sheets(Sheets.Count)).name = xName1
Sheets("Sheet1").Activate
Sheets is a collection of all sheets in the workbook. Since no workbook was specified, it assumes you are referencing the Active Workbook. Sheets(index) is a method used to access a specific member of the collection.
If no member exists that matches the given name, it returns the error that you've encountered. Which is to say, the active workbook at the time of execution did not contain a sheet with the name "Sheet2".
If you want to test if a sheet exists prior accessing it, wrap it with an error statement like:
On Error Resume Next
Set xSht = Sheets(xName)
If Not xSht Is Nothing Then
...
End If
On Error Goto 0
Excel is crashing every time I run the below code.
I'm trying to unhide names. There are a lot of them. I tried to copy a sheet and it took me forever to get rid of the name conflict messages.
Is there a way to unhide only some names at a time so Excel doesn't crash?
Sub Show_Hidden_Defined_Names()
Dim xName As Variant
For Each xName In ActiveWorkbook.Names
xName.Visible = True
Next xName
End Sub
Some names (particularly those that start with "_") are defined based on certain newer functions being used in your workbook or things like print regions. See if avoiding those will help:
Sub Show_Hidden_Defined_Names()
Dim xName As Name
For Each xName In ThisWorkbook.Names
If Left$(xName.Name, 1) <> "_" Then xName.Visible = True
Next
End Sub
Also, as shown above, it's a good idea in most cases to use ThisWorkbook rather than ActiveWorkbook. The latter refers to whichever workbook has focus, the former, to the one that contains the VBA code. They may not always be the same.
Use this code to see which Name causes the crash
Sub Show_Hidden_Defined_Names()
On Error Resume Next
Dim s As String:s = "No errors"
Dim xName As Name
For Each xName In ActiveWorkbook.Names
xName.Visible = True
If Err.Number <> 0 Then
s = xName.Name
Exit For
End If
Next xName
MsgBox s
End Sub
I've encountered a strange thing: I've joined three workbooks: Personal Data Tracker, Global Tracker and the workbook with pivots and charts. The logic is as it follows: the user clicks on a button after the work is finished so the data is copied to the GL Tracker. Once the change event is triggered in the GL Tracker Table, the last workbook opens, the pivot is refreshed upon the open vent and the wb is closed.
Everything seems to be working fine, however when I run the macro live, at the very end I get an error message about
"Application-defined or object-defined error".
Only OK and Help button displayed, it doesn't make the VBE Open so I could debug it.
Would anyone know what it may be happening even if the whole chain works fine?
Thank you.
Code from the Personal Tracker:
Sub test()
Dim path As String
Dim wb As Workbook
path = ThisWorkbook.path & "\Dest.xlsm"
Application.ScreenUpdating = False
ThisWorkbook.Sheets("Total").Range("R1").Value = Date
Range("R1").Font.Color = VBA.ColorConstants.vbWhite
Worksheets("TOTAL").Range("B2:B13").Copy
On Error GoTo Handler
Workbooks.Open (path)
On Error GoTo 0
Set wb = Workbooks("Dest")
Worksheets("Sheet1").Range("B2").PasteSpecial Paste:=xlPasteValues
Exit Sub
Handler:
MsgBox "Someone else is saving their data at the moment." & vbNewLine & _
"Please try in a few seconds"
End Sub
Code from the GL Tracker:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim MRange As Range
Dim wbPivot As Workbook
Dim pt As PivotTable
Dim ws As Worksheet
Dim Name As String
Dim answer As VbMsgBoxResult
Set MRange = ThisWorkbook.Sheets(1).Range("Table1")
Name = Application.UserName
Application.ScreenUpdating = False
If Not Intersect(Target, MRange) Is Nothing Then
Application.EnableEvents = True
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Pivot.xlsm")
End If
'refresh
For Each ws In wbPivot.Worksheets
For Each pt In ws.PivotTables
pt.PivotCache.Refresh
pt.Update
pt.RefreshTable
Next
Next
'saving
Application.ScreenUpdating = True
If Application.UserName <> "Jakub Tracz" Then
MsgBox "User not authorised. Workbook will be closed."
wbPivot.Close True
ThisWorkbook.Close True
Else
answer = MsgBox(Prompt:="Do you want to save and close the workbook?", _
Buttons:=vbYesNo + vbQuestion)
Select Case answer
Case vbYes
wbPivot.Close True
ThisWorkbook.Close True
Case vbNo
MsgBox "Welcome, " & Application.UserName
End Select
End If
End Sub
I'm going to give you a proof of concept code as an example for you to use. This will not exactly answer your question with code you can just copy/paste, but you will be able to use this to put it together the way you want it to work instead of me making assumptions about many things and restructuring it myself.
This simply demonstrates how to use a workbook object variable in one routine that can reference another workbook, and how to make changes to that 2nd workbook and save/close it.
Sub Tracker_Update()
Dim wbPivot as Workbook
' open the workbook
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Test.xlsx")
' optionally make it hidden
wbPivot.Visible = False
With wbPivot
' pretend this code updates the pivot table
.Worksheets(1).Range("A1") = "hello world"
' Close and save it
.Close True
End With
' optionally clear the variable
' this is not really needed in VBA, but if you eventually
' start using VB.NET with Excel as a COM object,
' you will want to know how to do this part when you are done
Set wbPivot = Nothing
End Sub
I think you will like this approach in the end much better in the end anyway, as the code isn't scattered around so much in different places. Easier to debug later, and easier for someone else to understand what you are doing if and when you leave the company.
I have a workbook that uses a macro and makes many sheets. After one sheet, called Paste, I want to be able to delete the sheets that follow once I am done using them.
I found the following code from https://stackoverflow.com/a/53544169/11615632 and slightly modified it to use in my workbook.
Sub Deleting()
Dim Indx As Long
Dim x As Long
With ThisWorkbook
On Error Resume Next
Indx = .Sheets("Paste").Index
On Error GoTo 0
If Indx <> 1 Then
If .Sheets.Count > 2 And Indx < .Sheets.Count Then
Application.DisplayAlerts = False
For x = .Sheets.Count To Indx + 1 Step -1
.Sheets(x).Delete
On Error GoTo 0
Next x
Application.DisplayAlerts = False
End If
Elseif Indx = 1 Then
Exit Sub
End If
End With
End Sub
However, when I do this it actually works, but I get an error message saying
"Run-time error '-2147319765':
Automation Error
Element not found.
The error is found on the line .Sheets(x).Delete
Since you know that you want to keep two specific sheets ("Value" and "Paste"), instead of using the indexes, which can be a little tricky and may not always work depending on the order/added order of them, I suggest instead looking at the name of each worksheet and delete that way (as mentioned in the comments).
Dim ws as Worksheet
' This next line will suppress the "Confirm Deleting" messagebox
' when you go to delete a worksheet
Application.DisplayAlerts = False
For each ws in ThisWorkbook.Worksheets
If ws.Name <> "Value" and ws.Name <> "Paste" Then
ws.Delete
End If
Next ws
Application.DisplayAlerts = True
(This assumes the macro is stored in the workbook you want to delete the sheets from. If it's not, perhaps it's stored in Personal.xlsb, then switch ThisWorkbook to ActiveWorkbook or something more specific.)
I have an Excel macro that creates another workbook for the user to modify. When I try to enter data in a cell in the new workbook, however, I get the error "The cell or chart you're trying to change is on a protected sheet." The sheet in the macro workbook is, in fact, protected, but that sheet is not visible at the time I get the error. When I try to close the visible, newly created workbook, it’s the macro workbook that closes. The last thing my macro does is activate the sheet in the new workbook. What do I have to do to make that work? Having the macro close its own workbook solves the problem, of course, but that’s not what I want to do, since the user needs another macro in the same workbook to process the changes on the new sheet.
The program has over 6000 lines of code (so far), but here is one of the routines that causes the problem.
Private Sub z3_BudgetPrepUpd()
'Build a new workbook initialized to let the user modify data
'for an existing fiscal-quarter budget.
'When this routine executes,
' UserForm1 is still active.
Dim strTracer As String 'error-handling tracer for this subroutine
Dim strFyrQtr As String
On Error GoTo abend
If blnAbort Then Exit Sub
If blnAbortGlobal Then Exit Sub
'Find out which ListBox item the user selected:
If UserForm1.ListBox1.ListCount < 1 Then GoTo aa9000 'ListBox is empty
If UserForm1.ListBox1.ListIndex < 0 Then 'No item selected
strMsgTitle = udtPrm.msgTtl
strMsgPrompt = "Please select a fiscal quarter to update."
Call z0_MsgBox
GoTo aa9000
End If
strFyrQtr = UserForm1.ListBox1.Value 'Selected item in ListBox
'Close UserForm1:
UserForm1.Hide
ThisWorkbook.Sheets(c_WKS_WELCOME).Activate
'Build the udtBgt() array with data for the specified quarter:
lngBgtHiNdx = -1
Call zz_GetBudgetForQtr(strFyrQtr)
If blnAbort Then GoTo aa9000
'Build a new workbook for the user to update budget amounts:
Workbooks.Add
Set wkbNewBook = ActiveWorkbook
'Save the names of the default worksheets
'so we can delete them later:
strDfltSheets() = z0_SheetNames(wkbNewBook)
'Build a worksheet with data from the udtBgt() array:
Call z3_BuildBudgetUpdSheet
If blnAbort Then GoTo aa9000
'Delete the default worksheets:
Call z0_DeleteSheets(wkbNewBook, strDfltSheets())
If blnAbort Then GoTo aa9000
wkbNewBook.Sheets(c_WKS_IPT_BUDGET).Activate
'Excel 2016 Bug:
'We need to close ThisWorkbook to allow the user
'to work with the book we just created:
Application.DisplayAlerts = False
ThisWorkbook.Close
aa9000:
Exit Sub
abend:
lngErr = Err.Number
strErr = Err.Description
blnAbort = True
Application.Cursor = xlDefault 'no more hourglass
strMsgTitle = "Program Error"
strMsgPrompt = "The following error occurred:" & Chr(10) & Chr(10) & _
"Error No. " & CStr(lngErr) & Chr(10) & _
"Error Description: " & strErr & Chr(10) & _
"Subroutine: z3_BudgetPrepUpd" & Chr(10) & _
"Tracer: " & strTracer
Call z0_MsgBox
Resume aa9000
End Sub
You use ThisWorkbook which I agree with. You use ActiveWorkbook which I hardly ever use.
I'd recommend using a variable to store reference to workbooks other than that which houses your code. So use
Dim wb As Excel.Workbook
Set wb = Application.Workbooks.Open("c:\test.xlsm") 'for opening
'* or
Set wb = Application.Workbooks.Add 'for creating a new one
'* or
Set wb = Application.Workbooks.Item("AlreadyOpen.xlsm") 'for referencing one already open
'* from hereon use wb instead of ActiveWorkbook
wb.Worksheets.Item(1).Visible = True
Thanks, everyone, for your interest and suggestions. I have solved the problem by redesigning the application without UserForms or external workbooks. Office 2016 has many issues, and perhaps this is one of them. In any case, I have no more time to research it.