Excel VBA index out of bounds while using Sheets.delete - excel

After a few iterations of the following code I always get the error that the index was out of bounds.
For i = myworksheet.index To Worksheets.count
Sheets(i).delete
Next i

You shouldn't delete sheets this way.
Consider what you're asking it to do. Let's say you have 5 worksheets- Sheet1, Sheet2.. Sheet 5.
Let's say myworksheet is Sheet3 (i=3).
When the loop starts, i is 3.
Sheet3 is deleted.
The loop restarts and i is now 4.
However, there are now only 4 worksheets. So Sheet5 (i=4) is deleted.
The loop restarts and i is now 5.
However, there are now only 3 worksheets. There is no worksheet with index of 5 to delete.
One (of many) ways to achieve your goal is to do the following:
i = myworksheet.Index
Do Until Worksheets.Count = i - 1
Worksheets(Worksheets.Count).Delete
Loop
One thing to point out with this.. in your code, you appear to be deleting your start sheet myworksheet. Because of this, the Do Until... loop I've created finishes at i-1 to stop after myworksheet is deleted. If you didn't want this to happen, remove the - 1. If you did want this to happen, you need to be aware that it will error if the index of myworksheet is 1 - as all workbooks must contain at least 1 worksheet.

Try the next way, please. In your code, after sheets deleting, the reference not make sense for i bigger then existing maximum (remained) one:
Sub deleteSheets()
Dim sh As Worksheet, ws As Worksheet
Set sh = ActiveSheet
For Each ws In ActiveWorkbook.Sheets
If ws.Index > sh.Index Then
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End If
Next
End Sub
Or looping backwards, as #SJR suggested:
Sub deleteSheetsBis()
Dim myworksheet As Worksheet, i As Long
Set myworksheet = ActiveSheet
For i = ActiveWorkbook.Worksheets.count To myworksheet.Index Step -1
Application.DisplayAlerts = False
Sheets(i).Delete
Application.DisplayAlerts = True
Next i
End Sub

Related

Delete multiple Excel Sheets in VBA

I am using an excel Workbook for programtical generation. Once the workbook is created few of the sheets are having required data and few are blank with default templates only.
I need to delete all sheets having default templates (means no data). I can check specific cell to identify this however need to know how to check for all sheets and then delete sheets one by one.
I am having this piece of code:
Sub TestCellA1()
'Test if the value is cell D22 is blank/empty
If IsEmpty(Range("D22").Value) = True Then
MsgBox "Cell A1 is empty"
End If
End Sub
Try this:
Sub DeleteEmptySheets()
Dim i As Long, ws As Worksheet
' we don't want alerts about confirmation of deleting of worksheet
Application.DisplayAlerts = False
For i = Worksheets.Count To 1 Step -1
Set ws = Worksheets(i)
' check if cell D22 is empty
If IsEmpty(ws.Range("D22")) Then
Sheets(i).Delete
End If
Next
' turn alerts back on
Application.DisplayAlerts = True
End Sub
An alternative implementation using For-Each:
Sub deleteSheets()
Dim wb As Workbook
Dim sht As Worksheet
Set wb = Workbooks("Name of your Workbook")
'Set wb = ThisWorkbook You can use this if the code is in the workbook you want to work with
Application.DisplayAlerts = False 'skip the warning message, the sheets will be deleted without confirmation by the user.
For Each sht In wb.Worksheets
If IsEmpty(sht.Range("D22")) And wb.Worksheets.Count > 1 then
sht.Delete
End If
Next sht
Application.DisplayAlerts = True
End Sub
This mainly serves as a demonstration pf how you can easily loop through worksheets.
As suggested in the comments below by #Darren Bartrup-Cook , the logic according to which the sheets are deleted can and should be modified to not only suit your purposes but to also include safeguards.
Making sure there's always at least one worksheet in the workbook is one of them. This can be ensured in a multitude of ways. I updated my answer to implement one these.

For each in VBA - starting from third stylesheet

I've hot many stylesheets in Workbook in Excel and I need to make some changes in almost every stylesheet. First two of them and last few should be skipped.
I'm using For Each loop and really don't have idea how to skip 2 first elements. With the last ones is not problem, because I check the stylesheet's name and if it's equal to my condition I'm breaking the loop and exit.
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
If ws.Name = "03.2016PTF" Then Exit For
'here's my code
Next
If I will exit from loop at start I won't do changes in the rest of documents.
Try:
With ThisWorkbook
maxsht = .Sheets.Count
For i = 3 To maxsht
If .Sheets(i).Name = "03.2016PTF" Then Exit For
'here's my code
Next i
End With
It loops through all sheets using the Index, so effectively you can start at the nth sheet, in this case the third.
The code loops until the last sheet in the wb unless it encounters the aforementioned sheet named 03.2016PTF, at which the loop exits.
Using And on the if statement to check for more criterias.
Or any of them could trigger the if.
And them all must be true so the if is triggered.
This way you can fill in as much sheets as you need and won't worry about their order.
Dim ws As Worksheet, arrWs As Variant, Skiped As Boolean
arrWs = Array("Sheet1ToAvoid", "Sheet2ToAvoid", "...") 'fill this with as much sheets you need
For Each ws In ThisWorkbook.Worksheets
Skiped = Application.Match(ws.Name, arrWs, 0)
If Not Skiped Then
'here's my code
End If
Next

Deleting Sheets With One Row Excel VBA

I am creating some sheets and would like to delete the ones with only one row. I have tried following two codes but they did not work.
WSCount = Worksheets.Count
For l = 1 To WSCount
Worksheets(l).Activate
If IsEmpty(ActiveSheet.Cells(2, 1)) Then
ActiveSheet.Delete
WSCount = WSCount - 1
l = l - 1
End If
Next l
Below is the second one.
For Each Worksheet in ActiveWorkbook.Worksheets
If IsEmpty(ActiveSheet.Cells(2,1)) Then
ActiveSheet.Delete
End If
Next
The problem I am encountering is when I delete pages, it messes with the for loop. This directly happens at the first code. In the second code, the problem is that I am not activating that sheet so excel does not delete it. I have to put a for loop in that one too, which makes me encounter the same problem at the first code.
There is probably a simple solution but my knowledge is limited so all I could think is putting a for loop.
That's why we always loop backwards when deleting sheets, rows, columns ...
Sub x()
Dim WSCount As Long, l As Long
WSCount = Worksheets.Count
For l = WSCount To 1 Step -1
If IsEmpty(Worksheets(l).Cells(2, 1)) Then
Worksheets(l).Delete
End If
Next l
End Sub
As Scott says, your second bit of would work thus as in your existing code the activesheet never changes so you would only ever delete a single sheet.
For Each Worksheet in ActiveWorkbook.Worksheets
If IsEmpty(worksheet.Cells(2,1)) Then
worksheet.Delete
End If
Next
Also read up on how to avoid select.
Sub deleteSheet()
Application.DisplayAlerts = False
For Each sh In ThisWorkbook.Worksheets
If IsEmpty(sh.Cells(2, 1).Value) Then
sh.Delete
End If
Next
Application.DisplayAlerts = True
End Sub

Run Macro that has two For and If statements

I am trying to run a macro that will remove any rows that have a #REF! as well as remove the header. On top of all of that, I would also like for the macro to go through and apply this option for all worksheets except the first one.
When I try to run it acts as if it worked, but when I checked the specific worksheets where this applies nothing has happened.
Sub RemoveGamesOut()
Dim i As Long
Dim ws As Worksheet
Application.ScreenUpdating = False
For Each ws In Worksheets
If ws.Name <> "1962-63 Stats" Then ws.Range ("C6:C5000").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
For i = Range("C" & Rows.Count).End(3).Row To 5 Step -1
If IsError(Cells(i + 1, "C")) = True Then Rows(i).Resize(2).Delete
Next i
Next ws
End Sub

Obtain displayed order of Excel worksheets

I'd like to find the position of a worksheet as it is displayed in a workbook.
For example, assume I have a workbook starting with Sheet1, Sheet2 and Sheet3 in that order. Then a user drags Sheet2 to left, before Sheet1.
I want Sheet2 to return 1, Sheet1 to return 2 (and Sheet3 still to return 3).
I can't find a way to determine this in VBA.
This should do it:
Worksheets("Sheet1").Index
https://msdn.microsoft.com/en-us/library/office/ff836415.aspx
You can just iterate the Worksheets collection of the Workbook object. You can test yourself by running the following code, switch the order around in the UI, then run it again:
Option Explicit
Sub IterateSheetsByOrder()
Dim intCounter As Integer
Dim wb As Workbook
Set wb = ThisWorkbook
For intCounter = 1 To wb.Worksheets.Count
Debug.Print wb.Worksheets(intCounter).Name
Next intCounter
End Sub
To loop through all worksheets in a workbook use For Each WS in ThisWorkbook.Worksheets where WS is a worksheet object. Hence to obtain order of Excel worksheets as shown, we may also use the following code:
Sub LoopThroughWorksheets()
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
Debug.Print WS.Name
Next
End Sub
To obtain an output like Worksheets("Sheet1").Index then you may use this code
Sub IndexWorksheet()
Dim WS As Worksheet, n As Long
For Each WS In ThisWorkbook.Worksheets
n = n + 1
If WS.Name = "Sheet1" Then Debug.Print n
Next
End Sub
You can use the Sheets object. In your example, reading Sheets(2).Name should return Sheet1.
Right answer provided by Anastasiya-Romanova, but missing some important details.
There are two methods of doing this. First, with a For Each loop:
Sub ListSheetNames()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Next ws
End Sub
Second, with a basic For loop:
Sub ListSheetNames
Dim i As Long
For i = 1 to ThisWorkbook.Worksheets.Count
Debug.Print ThisWorkbook.Worksheets(i).Name
Next i
End Sub
You will find the second method will always output the names in the sheet index order, which is generally the order the sheets were created in unless you change the index. Simply rearranging the sheets from the workbook window won't change the index.
Therefore, the first method is the correct way to do this. It will always follow the tab order as you see on your screen.
Below code works even if sheet is renamed or its sequence is changed.
Sub Display_Sheet_Tab_Number()
Dim WorksheetName As String
Dim n As Integer
WorksheetName = Sheet1.Name
MsgBox Worksheetname
n = Sheets(WorksheetName).Index 'n is index number of the sheet
MsgBox "Index No. = " & n
End Sub

Resources