I have this small piece of code:
NombreLibro = Application.GetOpenFilename()
Set Libro = Workbooks.Open(NombreLibro, , False)
If Val(Application.Version) > 15 Then 'I tried this but it doesn't solve the problem
Libro.AutoSaveOn = False
End If
With Libro
For i = 1 To .Worksheets.Count
If .Worksheets(i).CodeName = "Sheet1" Then 'HERE I HAVE THE PROBLEM
(doing something)
End If
Next i
End With
Sometimes the "if" is false even if the workbook actually has the "Sheet1".
But if I run this again, adding a stop in the code to check what is going on, then the piece of code works as expected.
I am downloading the workbooks from a company website and run the code right away.
I have OneDrive in my computer. So I am wondering if OneDrive is busy uploading the file and then Excel doesn't access it correctly?
What do you suggest I could try?
EDIT:
Following VBasic2008 suggestion (see his/her answer) I changed a little the code, but it kept failing. I then added a debug MsgBox:
For Each ws In Libro.Worksheets
MsgBox "CodeName: " & ws.CodeName & vbLf _
& "Name: " & ws.Name & vbLf & "Libro: " & Libro.Name 'I added this
If ws.CodeName = wsCodeName Then
wasFound = True
Exit For ' The worksheet is found, no need to loop anymore.
End If
Next ws
Result (shown in the MsgBox):
CodeName: 'blank!!!
Name: SheetName 'correct
Libro: LibroName 'correct
Is there a bug in Excel related to CodeNames?
EDIT2: (WORKAROUND)
I download the files from a company website, the data on the website is on a table and then a converter downloads it into Excel format.
I think the downloaded file is not quite Excel format and the CodeName is not filled. When Excel opens it and then the VBA editor is opened, Excel fills out the CodeName with a standard name.
In my case, as the fresh downloaded files have only one sheet, I can use this workaround:
For Each ws In Libro.Worksheets
If ws.CodeName = wsCodeName Or ws.CodeName = "" Then
wasFound = True
Exit For
End If
Next ws
This will work the first time the file is processed ws.CodeName = "" and the next times ws.CodeName = wsCodename
Using Worksheet CodeName
Option Explicit
Sub testCodeName()
Const wsCodeName As String = "Sheet1"
' Choose file (workbook, spreadsheet).
Dim NombreLibro As Variant
NombreLibro = Application.GetOpenFilename()
' Validate workbook.
If NombreLibro = False Then
MsgBox "You canceled.", vbExclamation, "Canceled"
Exit Sub
End If
' Open and create a reference to the workbook.
Dim Libro As Workbook: Set Libro = Workbooks.Open(NombreLibro, , False)
' Attempt to find the worksheet.
Dim ws As Worksheet
Dim wasFound As Boolean
For Each ws In Libro.Worksheets
If ws.CodeName = wsCodeName Then
wasFound = True
Exit For ' The worksheet is found, no need to loop anymore.
End If
Next ws
' Validate worksheet.
If Not wasFound Then
MsgBox "Worksheet not found.", vbExclamation, "Not Found"
Exit Sub
End With
' Continue with the code
With ws
' e.g. see if it's true.
MsgBox "Worksheet found:" & vbLf _
& "Name: " & .Name _
& vbLf & "CodeName: " & .CodeName, vbInformation, "Success"
End With
End Sub
I'm somewhat of a VBA noob but I wrote this simple code a while back to search for a worksheet and delete it:
Dim sht As Worksheet
For Each sht In ThisWorkbook.Worksheets
If Application.Proper(sht.Name) = Application.Proper("Company Data") Then
Sheets("Company Data").Select
Application.DisplayAlerts = False
ActiveWindow.SelectedSheets.Delete
Application.DisplayAlerts = True
End If
Next sht
Maybe this can help?
Related
I am trying to delete a sheet using macro and also the corresponding text containing the sheet name which was deleted is also to be deleted from the table in column BP simultaneously. Everything is working well. But when I close excel and open and run the script again. The sheet which was previously deleted again appears back. I am attaching the code as shown below
Kindly help. What could be the reason for this?
Private Sub CommandButton2_Click()
Dim xWs As Worksheet
Dim wb As Workbook
Dim sheetName As String
Dim z As Long
Dim last As Long
ThisWorkbook.Activate
sheetName = Application.InputBox("Please enter the OSAT Name:", "OSAT", _
, , , , , 2)
last = ThisWorkbook.Worksheets("DataStorage").Cells(Rows.Count, "BP").End(xlUp).Row
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Err.Clear
On Error Resume Next
Set xWs = Sheets(sheetName)
If Err <> 0 Then
MsgBox "The OSAT '" & sheetName & "'" & "does not exist!", vbInformation, "Excel 10 Tutorial"
Exit Sub
Else
xWs.Delete
MsgBox "The OSAT '" & sheetName & "'" & "has been deleted!", vbInformation, "Excel 10 Tutorial"
For z = last To 2 Step -1
If ThisWorkbook.Worksheets("DataStorage").Cells(z, "BP").Value = sheetName Then
Sheets("DataStorage").Cells(z, "BP").Delete
End If
Next z
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
The guidelines contained in the previous comments are very important and must be followed.
To temporarily test for a solution, try this, substituting xWs.Delete with these lines:
Dim oWB As Excel.Workbook
Set oWB = xWs.Parent
xWs.Delete
oWB.Save
I am trying to delete a sheet using macro and also the corresponding text containing the sheet name which was deleted is also to be deleted from the table in column BP simultaneously. Everything is working well. But when the script is used as add in then The sheet which was previously deleted again appears back. I am attaching the code as shown below
Kindly help. What could be the reason for this?
Private Sub CommandButton2_Click()
Dim xWs As Worksheet
Dim wb As Workbook
Dim sheetName As String
Dim z As Long
Dim last As Long
ThisWorkbook.Activate
sheetName = Application.InputBox("Please enter the OSAT Name:", "OSAT", _
, , , , , 2)
last = ThisWorkbook.Worksheets("DataStorage").Cells(Rows.Count, "BP").End(xlUp).Row
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Err.Clear
On Error Resume Next
Set xWs = Sheets(sheetName)
If Err <> 0 Then
MsgBox "The OSAT '" & sheetName & "'" & "does not exist!", vbInformation, "Excel 10 Tutorial"
Exit Sub
Else
xWs.Delete
MsgBox "The OSAT '" & sheetName & "'" & "has been deleted!", vbInformation, "Excel 10 Tutorial"
For z = last To 2 Step -1
If ThisWorkbook.Worksheets("DataStorage").Cells(z, "BP").Value = sheetName Then
Sheets("DataStorage").Cells(z, "BP").Delete
End If
Next z
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Thisworkbook references the Add-Ins file. If you close Excel the add-in won't get saved. Therefore the deletion is reset.
You need to add this to the Thisworkbook module
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Thisworkbook.save
End Sub
BUT: are you sure you want to save data in an Add-In?
The goal is to create a copied sheet that is renamed in the current month and year. The copied sheet is being created in the workbook, however a default name is given to the sheet. What am I missing?
Private Sub Button3_Click()
Dim wb As Workbook
Dim ws As Worksheet
Dim nowMonth As Integer, nowYear As Integer
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
nowMonth = Month(Now)
nowYear = Year(Now)
Set wb = ActiveWorkbook
On Error Resume Next
Set ws = wb.Sheet(nowMonth & ", " & nowYear)
On Error GoTo 0
If Not ws Is Nothing Then
MsgBox "The Sheet called " & nowMonth & ", " & nowYear & " already exists in the workbook.", vbExclamation, "Sheet Already Exists!"
Exit Sub
Else
Set ws = ActiveSheet.Copy(after:=wb.Sheets(wb.Sheets.Count))
ws.Name = nowMonth & ", " & nowYear
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
The problem is in Set ws = ActiveSheet.Copy(after:=wb.Sheets(wb.Sheets.Count)), because it is trying to Copy and Set in the same time and this is a bit too much.
Change the code in the condition to this:
If Not ws Is Nothing Then
MsgBox "something"
Exit Sub
Else:
Set ws = ActiveSheet
ws.Copy after:=wb.Sheets(wb.Sheets.Count)
wb.Worksheets(wb.Sheets.Count).Name = nowMonth & ", " & nowYear
End If
In general, avoid using Active and Select in VBA - How to avoid using Select in Excel VBA.
Worksheet.Copy disappointingly doesn't return a reference to the created sheet. Instead, it has the side-effect of adding a new sheet to the workbook, and activating it.
So after running Worksheet.Copy, the ActiveSheet is the newly created sheet.
ActiveSheet.Copy after:=wb.Sheets(wb.Sheets.Count)
ActiveSheet.Name = nowMonth & ", " & nowYear
Now, this code is confusing/misleading, because it looks like the two statements are qualified with the same object, but they aren't.
What's not clear, is why and how the ActiveSheet is guaranteed to be the correct sheet to copy; we're working off the ActiveWorkbook and we don't really care which sheet is active.
I'd suggest to make the copy work off an explicit sheet:
Dim sourceSheet As Worksheet
Set sourceSheet = wb.Sheets(wb.Sheets.Count)
sourceSheet.Copy after:=sourceSheet '<~ new sheet becomes ActiveSheet
ActiveSheet.Name = nowMonth & ", " & nowYear
And now everything is as clear as it gets.
I have a workbook with many sheets. I am webscraping with numbers, and then making each sheet have the number as the name. I want to display an error if the number has already been given to a sheet. I also want the user to be able to enter a new sheetname if so, but the program keeps popping up its own error message before I can do this.
The number is in cell D10 in the worksheet.
For Each Sheet In ThisWorkbook.Sheets
If Sheet.Name = Range("D10") Then
MsgBox ("ERROR: This Acct No has already been formulated")
NewName = InputBox("Please Rename:")
ActiveSheet.Name = NewName
ElseIf Sheet.Name <> Range("D10") Then
ActiveSheet.Name = Range("D10")
End If
Next Sheet
I expect my own message to pop up, but Excel just pops its own error message.
try this:
Dim MyDuplicate as boolean
MyDuplicate = False
For Each Sheet In ThisWorkbook.Sheets
If Sheet.Name = Range("D10") Then
MsgBox ("ERROR: This Acct No has already been formulated")
NewName = InputBox("Please Rename:")
ActiveSheet.Name = NewName
MyDuplicate = True
Exit for
End If
Next Sheet
If MyDuplicate = False then ActiveSheet.Name = Range("D10")
BTW, I do recommend you avoid using ActiveSheet and assign the sheet to a variable instead.
Option Explicit
Sub TestMe()
Dim wks As Worksheet
Worksheets.Add After:=ActiveSheet
For Each wks In ThisWorkbook.Worksheets
With wks
If .Name = .Range("D10") Then
MsgBox ("ERROR: This Acct No has already been formulated")
.Name = InputBox("Please Rename:")
ElseIf .Name <> .Range("D10") Then
If Trim(.Range("D10")) = "" Then
.Range("D10") = Replace(Replace(Now, ":", "_"), "/", "_")
Application.Wait Now + #12:00:02 AM#
End If
.Name = .Range("D10").Value
End If
End With
Next wks
End Sub
This is some idea how to do it, avoiding the Activate and Select, as per the How to avoid using Select in Excel VBA
(Ironically, I have left Worksheets.Add After:=ActiveSheet)
The part .Range("D10") = Replace(Replace(Now, ":", "_"), "/", "_") writes the current date and time, making sure it is always a unique one, by waiting 2 seconds on the next line - Application.Wait Now + #12:00:02 AM#
Rather than looping every sheet to check for duplicates, create a function that returns a boolean. This function will have an error if the sheet doesn't exist, and no error if the sheet does exist. We check for that error, and return True if sheet exists, False otherwise.
Option Explicit
Private Function SheetExists(wsName As String, Optional wb As Workbook = Nothing) As Boolean
Dim ws As Worksheet
On Error Resume Next
If wb Is Nothing Then
Set ws = Worksheets(wsName)
Else
Set ws = wb.Worksheets(wsName)
End If
SheetExists = (Err.Number = 0)
End Function
And then your code could be replaced with the following, which will keep calling on the InputBox as many times as necessary in order to prevent the user from inputting another invalid/duplicate entry. For this, I've combined the MsgBox and InputBox text, seems unnecessary to throw two prompts at the user when we can use the InputBox to both inform and ask for new input.
Dim ws as Worksheet
Dim newName as String
Set ws = ActiveSheet ' would be better to avoid this, but OK.
newName = Range("D10").Value
While SheetExists(newName, ws.Parent)
newName = InputBox("ERROR: This Acct No has already been formulated!" & vbCrLf & vbCrLf & _
newName & " already exists! Enter new name:")
Wend
ws.Name = newName
I am working on a Userform that will copy a specific sheet from Workbook A and paste it into Workbook B (essentially archiving that data). The Userform presents the user with a combo-box dropdown to select the sheet name to be copied. I receive a subscript out of range error however when using the sheets.copy command. Here is my code with names modified for ease of reading:
Dim ws as Worksheet
Dim WorkbookA as Workbook
Dim WorkbookB as Workbook
Dim ComboBoxValue as String
Set WorkbookA as ActiveWorkbook
Set WorkbookB as Workbook.Open("C:File Path Here")
With ThisWorkbook
For Each ws In Application.ActiveWorkbook.Worksheets
If ws.Name = UserForm1.ComboBox1.Text Then
ComboBoxValue = ws.Name
Worksheets(ComboBoxValue).Copy _
After:=Workbooks("Workbook B.xlsm").Sheets(Sheets.Count)
' Run-Time 9 Subscript Out of Range Error occurs on line above ^
ActiveSheet.Name = UserForm1.ComboBoxSelection.Text
WorkbookB.Save
WorkbookB.Close
WorkbookA.Activate
Application.CutCopyMode = False
End If
Next ws
End With
The root of your error is improper refenceing of the workbook. There are a lot of other issues, too.
Unnecassary reference to ThisWorkbook
Unnecassary loop through all worksheets
Unnecassary renaming of copied sheet
Unnecassry / incorrect references to the ActiveWorkbook and ActiveSheet
No Error Handling
Improper indenting
Your code, refactored. This is written as a button click event in the UserForm. Update to suit your needs.
Option Explicit
Const ArchiveFilePath As String = "C:\Path\To\ArchiveBook.xlsx"
Private Sub CommandButton1_Click()
Dim ws As Worksheet
Dim WorkbookA As Workbook
Dim WorkbookB As Workbook
Dim wsName As String
Application.ScreenUpdating = False
Set WorkbookA = ActiveWorkbook
wsName = UserForm1.ComboBox1.Text
If wsName = vbNullString Then Exit Sub
On Error Resume Next 'Handle possibility that Open fails
Set WorkbookB = Workbooks.Open(ArchiveFilePath)
On Error GoTo 0
If WorkbookB Is Nothing Then
MsgBox "Failed to open " & ArchiveFilePath, vbOKOnly, "Error"
Exit Sub
End If
'Check if specified ws already exists in WorkbookB
Set ws = GetWorksheet(WorkbookB, wsName)
If Not ws Is Nothing Then
' Sheet already exists. What now?
MsgBox "Sheet " & wsName & " already exists in " & WorkbookB.Name & ". What now?", vbOKOnly, "Error"
WorkbookB.Close
Exit Sub
End If
Set ws = GetWorksheet(WorkbookA, wsName)
If ws Is Nothing Then
MsgBox "Sheet " & wsName & " does not exist in " & WorkbookA.Name, vbOKOnly, "Error"
WorkbookB.Close
Exit Sub
End If
ws.Copy After:=WorkbookB.Sheets(WorkbookB.Sheets.Count)
WorkbookB.Save
WorkbookB.Close
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Private Function GetWorksheet(wb As Workbook, wsName As String) As Worksheet
On Error GoTo EH
Set GetWorksheet = wb.Worksheets(wsName)
EH:
End Function
Change Sheets(Sheets.Count) to Sheets(Workbooks("Workbook B.xlsm").Sheets.Count)
In this context, Sheets(Sheets.Count) is referring to your source workbook object, so you must specify to count the sheets in the other book.