I have a problem with my code whereby everything works fine except one line that keeps getting the automation error even though the sheet exists. My code is supposed to delete sheets based on a certain name column and despite editing it, the error still occurs. Would appreciate if someone could help me out here, thanks!
Sub DeleteSelectedSheets()
Const lngNameCol = 8 ' names in column (H)
' lngRow = 5 ' data start in row 5
Dim i As Long
Dim lastrow As Long
Dim row_num As Long
Dim wsh_to_delete As Worksheet
Dim main_sheet As Worksheet
Dim ws As Worksheet
Set main_sheet = ActiveSheet
lastrow = main_sheet.Range("A" & main_sheet.Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
For Each ws In ActiveWorkbook.Worksheets
For row_num = 5 To lastrow
If Not ws Is Nothing Then
If ws.Name = main_sheet.Cells(row_num, lngNameCol).Value Then
On Error Resume Next
Application.DisplayAlerts = False
Worksheets(ws.Name).Delete
Application.DisplayAlerts = True
On Error GoTo 0
End If
End If
Next
Next
End Sub
The automation error occurs here:
If ws.Name = main_sheet.Cells(row_num, lngNameCol).Value Then
Although the code deleted the sheets, the error keeps popping out after every row
I think the problem lies in the deletion of the worksheet during the loop.
Try your loops the other way around, cycling through each sheet to see if it is the name you're looking for:
For row_num = 5 To lastrow
For Each ws In ActiveWorkbook.Worksheets
If Not ws Is Nothing Then
If ws.Name = main_sheet.Cells(row_num, lngNameCol).Value Then
On Error Resume Next
Application.DisplayAlerts = False
Worksheets(ws.Name).Delete
Application.DisplayAlerts = True
On Error GoTo 0
End If
End If
Next
Next
When you delete element from a collection, the whole collection is a bit "unhappy". With the worksheets, the best way is to loop from the total count of the worksheets to 1 and check whether your worksheet should be deleted:
Sub TestMe()
Dim i As Long
For i = Worksheets.Count To 1 Step -1
If Worksheets(i).Name = "Something" And Worksheets.Count > 1 Then
Application.DisplayAlerts = False
Worksheets(i).Delete
Application.DisplayAlerts = True
End If
Next
End Sub
Additionally, there is a rule for Worksheets.Count>1, because the last worksheet of the workbook cannot be deleted.
Related
Sub um_separatabelanosfiltros()
Dim r As Integer, brand As String, ws As Worksheet
Set ws = ActiveSheet
ws.Range("A1:C1").AutoFilter
r = 1
Do
r = r + 1
brand = ws.Range("A" & r).Value
On Error Resume Next
If Sheets(brand) Is Nothing Then
ws.Range("A1:C1").AutoFilter field:=1, Criteria1:=brand
ws.Range("A1").CurrentRegion.SpecialCells(xlCellTypeVisible).Copy
Sheets.Add.Name = brand
Sheets(brand).Paste
ws.ShowAllData
End If
Loop While ws.Range("A" & r + 1).Value <> ""
End Sub
With this code i can separate a worksheet by the filters in the A1 cell, but i tried to use it in a different dataset and it kept creating empty worksheets, any sugestion and or help?
Iv tried alot of thing and my conclusion is that some how the data is screwing it up, i just dont know how it can do that or how to fix it
If you don't have a ready list of unique items in the column you want to split on, you can do it without autofilter:
Sub um_separatabelanosfiltros()
Dim brand As String, wsData As Worksheet, wsBrand As Worksheet
Dim wb As Workbook, cBrand As Range
Set wb = ActiveWorkbook
Set wsData = ActiveSheet
Set cBrand = wsData.Range("A2") 'first brand
Do While Len(cBrand.Value) > 0
brand = cBrand.Value
Set wsBrand = Nothing 'clear sheet reference
On Error Resume Next 'ignore error if no sheet match
Set wsBrand = wb.Worksheets(brand)
On Error GoTo 0 'stop ignoring errors ASAP
If wsBrand Is Nothing Then 'need to create a new sheet?
Set wsBrand = wb.Worksheets.Add(after:=wb.Worksheets(wb.Worksheets.Count))
wsBrand.name = brand
wsData.Rows(1).Copy wsBrand.Range("A1") 'copy headers
End If
cBrand.EntireRow.Copy wsBrand.Cells(Rows.Count, 1).End(xlUp).Offset(1)
Set cBrand = cBrand.Offset(1) 'Next row of data
Loop
End Sub
I am writing a macro to validate something in each sheet.
If the sheet contains the required info, it's kept, otherwise deleted. But my problem is, once the sheet is deleted focus goes automatically to the next sheet. hence, when the code hits the next sheet it actually skips one sheet in middle.
I have tried the below code :
Sub filterdelete()
Dim current As Workbook
Dim sht As Worksheet
Dim rowN As Integer
Set current = ActiveWorkbook
On Error Resume Next
For Each sht In current.Worksheets
If sht.Name <> "hiddensheet" Then
With sht
.Select
.Range("A1").Select
End With
rowN = Cells(Rows.count, 1).End(xlUp).Row
Application.DisplayAlerts = False
If rowN = 1 Then ActiveSheet.Delete
Application.DisplayAlerts = True
End If
Next sht
End Sub
I tried GoTo, also. But it is deleting every sheet. :(
You have to iterate over the worksheets in your workbook in reverse order so that deleting a sheet does not result in an unwanted behavior.
Try something like this:
For i = current.Worksheets.Count To 1 Step -1
// your code here
Next i
Use a counter variable in your loop and go backwards.
Also, use Long rather than Integer in case you have more rows than latter can handle.
Sub filterdelete()
Dim current As Workbook
Dim sht As Worksheet
Dim rowN As Long, i As Long
Set current = ActiveWorkbook
For i = current.Worksheets.Count To 1 step -1
If current.Sheets(i).Name <> "hiddensheet" Then
With current.Sheets(i)
rowN = .Cells(Rows.Count, 1).End(xlUp).Row
Application.DisplayAlerts = False
If rowN = 1 Then .Delete
Application.DisplayAlerts = True
End With
End If
Next i
End Sub
I have done an extensive amount of research on this topic but no luck so far.
I have moderate experience with programming.
That said my issue is in regards to reading data from a column and deleting the worksheet if certain text is read 47 times.
In Column "L" text ("n/m") is repeated 47x times. Text always begins in row 14 and always goes on until row 70. Within that range there are spaces and
"--------"
If that column has 47 "n/m" then the worksheet can be deleted and it has to be applied/repeated for the whole workbook which contained around 40 to 100 worksheets.
My code:
First try didn't work
Sub DeletingBlankPages()
Dim Ws As Worksheet
Dim nm As Range
Set nm = Ws.Range(Columns("12"))
Application.ScreenUpdating = False
For Each Ws In ActiveWorkbook.Worksheets
nm.Select
If nm Is "n/m" Then
Application.DisplayAlerts = False
Ws.Delete
Application.DisplayAlerts = True
End If
Next Ws
End Sub
Second try still didnt work
Sub DeleteRowBasedOnCriteria()
Dim Ws As Worksheet
For Each Ws In ActiveWorkbook.Worksheets
Application.DisplayAlerts = False
If Range(Columns("12")).Value < 47 > "n/m" _
Then _
Ws.Delete
Application.DisplayAlerts = True
End If
Next Ws
End Sub
If any of you with experience know how to solve this please respond.
Thank you
If I understand correctly, try this
Sub DeleteRowBasedOnCriteria()
Dim i As Long
For i = Sheets.Count To 1 Step -1
If WorksheetFunction.CountIf(Sheets(i).Range("L14:L70"), "n/m") >= 47 Then
If Sheets.Count > 1 Then
Application.DisplayAlerts = False
Sheets(i).Delete
Application.DisplayAlerts = True
Else
MsgBox "Only 1 sheet left"
Exit Sub
End If
End If
Next i
End Sub
Try this:
Sub DeleteRowBasedOnCriteria()
Dim Ws As Worksheet
Dim Counter As Integer
Application.DisplayAlerts = False
Application.ScreenUpdating = False
For Each Ws In ActiveWorkbook.Worksheets
Counter = 0
For i = 14 To 70
If Ws.Cells(i, 12) = "n/m" Then
Counter = Counter + 1
End If
Next i
If Counter >= 47 Then
Ws.Delete
End If
Next Ws
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I was attempting to loop through every worksheet in every workbook in a folder and make sure only the cells containing formulas were locked. I have already been using code to lock all cells in every worksheet, and code to lock every formula in a worksheet, successfully for a few months, so I basically mashed the two pieces of code together to get this:
Sub LockAllFormulas()
Dim myOldPassword As String
Dim myNewPassword As String
Dim ws As Worksheet
Dim FileName As String
Dim rng As Range
myOldPassword = InputBox(Prompt:="Please enter the previously used password.", Title:="Old password input")
myNewPassword = InputBox(Prompt:="Please enter the new password, if any.", Title:="New password input")
FileName = Dir(CurDir() & "\" & "*.xls")
Do While FileName <> ""
Application.DisplayAlerts = False
If FileName <> "ProtectionMacro.xlsm" Then
MsgBox FileName
Workbooks.Open (CurDir & "\" & FileName)
For Each ws In ActiveWorkbook.Worksheets
If Not Cells.SpecialCells(xlCellTypeFormulas) Is Nothing Then
ActiveWorkbook.ActiveSheet.Unprotect Password:=myOldPassword
ActiveWorkbook.ActiveSheet.Cells.Locked = False
For Each rng In ws.Cells.SpecialCells(xlCellTypeFormulas)
rng.Locked = True
Next rng
ActiveWorkbook.ActiveSheet.Protect Password:=myPassword
End If
Next ws
ActiveWorkbook.Save
ActiveWorkbook.Close
End If
FileName = Dir()
Loop
Application.DisplayAlerts = True
End Sub
Every time I run it it shows a 400 error. The error matches one I got whenever the code runs into a sheet that doesn't have any code in it, but I thought I fixed that problem when I added:
If Not Cells.SpecialCells(xlCellTypeFormulas) Is Nothing Then
Any ideas what else could be going wrong?
When working with SpecialCells, you have to be very careful. What I do is I store them in a range sandwiched between OERN and then check of they are not nothing. Here is an example
Dim rng As Range
On Error Resume Next
Set rng = ws.Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not rng Is Nothing Then
'
'~~> Rest of the code
'
End If
Applying that to your code will be like this (UNTESTED)
Dim LockedRange As Range
For Each ws In ActiveWorkbook.Worksheets
With ws
On Error Resume Next
Set LockedRange = .Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not LockedRange Is Nothing Then
.Unprotect Password:=myOldPassword
.Cells.Locked = False
LockedRange.Locked = True
.Protect Password:=myPassword
End If
Set LockedRange = Nothing
End With
Next ws
I have an existing worksheet "StudentSheet1" which I need to add as many times as a user needs.
For eg, if a user enters 3 in cell "A1", saves it and closes the workbook.
I want to have three sheets: "StudentSheet1" , "StudentSheet2" and "StudentSheet3" when the workbook is opened next time.
So I will have the Code in "Workbook_Open" event. I know how to insert new sheets, but cant insert this particular sheet "StudentSheet1" three times
Here is my code:
Private Sub Workbook_Open()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets.Add(Type:=xlWorksheet, After:=Worksheets(1))
Application.ScreenUpdating = True
End Sub
EDIT
Sorry I misread the question, try this:
Private Sub Workbook_Open()
Dim iLoop As Integer
Dim wbTemp As Workbook
If Not Sheet1.Range("A1").value > 0 Then Exit Sub
Application.ScreenUpdating = False
Set wbTemp = Workbooks.Open(Filename:="//Ndrive/Student/Student.xlsm")
wbTemp.Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
wbTemp.Close
Set wbTemp = Nothing
With Sheet1.Range("A1")
For iLoop = 2 To .Value
Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
ActiveSheet.Name = "StudentSheet" & iLoop
Next iLoop
.Value = 0
End With
Application.ScreenUpdating = True
End Sub
Why are you wanting to add sheets on the workbook open? If the user disables macros then no sheets will be added. As Tony mentioned, why not add the sheets when called by the user?
EDIT
As per #Sidd's comments, if you need to check if the sheet exists first use this function:
Function SheetExists(sName As String) As Boolean
On Error Resume Next
SheetExists = (Sheets(sName).Name = sName)
End Function
user793468, I would recommend a different approach. :)
wbTemp.Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
is not reliable. Please see this link.
EDIT: The above code will fail if the workbook has defined names. Otherwise it is absolutely reliable. Thanks to Reafidy for catching that.
I just noticed OP's comment about the shared drive. Adding amended code to incorporate OP's request.
Tried and Tested
Option Explicit
Const FilePath As String = "//Ndrive/Student/Student.xlsm"
Private Sub Workbook_Open()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim TempName As String, NewName As String
Dim ShtNo As Long, i As Long
On Error GoTo Whoa
Application.ScreenUpdating = False
Set wb1 = ActiveWorkbook
Set ws1 = wb1.Sheets("Sheet1")
ShtNo = ws1.Range("A1")
If Not ShtNo > 0 Then Exit Sub
Set wb2 = Workbooks.Open(FilePath)
Set ws2 = wb2.Sheets("StudentSheet1")
For i = 1 To ShtNo
TempName = ActiveSheet.Name
NewName = "StudentSheet" & i
If Not SheetExists(NewName) Then
ws2.Copy After:=wb1.Sheets(Sheets.Count)
ActiveSheet.Name = NewName
End If
Next i
'~~> I leave this at your discretion.
ws1.Range("A1").ClearContents
LetsContinue:
Application.ScreenUpdating = True
On Error Resume Next
wb2.Close savechanges:=False
Set ws1 = Nothing
Set ws2 = Nothing
Set wb2 = Nothing
Set wb1 = Nothing
On Error GoTo 0
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
'~~> Function to check if sheet exists
Function SheetExists(wst As String) As Boolean
Dim oSheet As Worksheet
On Error Resume Next
Set oSheet = Sheets(wst)
On Error GoTo 0
If Not oSheet Is Nothing Then SheetExists = True
End Function