VBA Deleting Active Sheet - excel

I am trying to create a macro that deletes the active sheet without displaying the prompt. Which is what the code below does...This works great until the last sheet. I get the prompt no matter what. I do not want to delete the last sheet and at the same time, I don't want the error '1004' message to come up. Is there a way to change the code above to not delete my last sheet and not display the error message at the same time?
Application.DisplayAlerts = False
ActiveSheet.Delete
Application.DisplayAlerts = True

If the idea is to delete the ActiveSheet and only it, this is something that will work, until there is only 1 sheet in the workbook:
Sub DeleteActiveSheet()
If ThisWorkbook.Worksheets.Count = 1 Then
Exit Sub
Else
Application.DisplayAlerts = False
ThisWorkbook.ActiveSheet.Delete
Application.DisplayAlerts = True
End If
End Sub
If the idea is to delete all worksheets, but the last, then follow this sequence:
assign a worksheet variable wksToStay from the type Worksheet and set it to the last worksheet in the workbook;
loop through all the Worksheets in the Workbook.Worksheets collection, starting from the last one;
always perform a check, whether the worksheet to be deleted wksToDelete has the same name as the wksToStay;
delete, if the name is not the same;
it will delete all the worksheets, including the hidden and the very hidden ones;
Sub DeleteAllButLast()
Dim wksToStay As Worksheet
Dim wksToDelete As Worksheet
Dim i As Long
Set wksToStay = ThisWorkbook.Worksheets(Worksheets.Count)
For i = Worksheets.Count To 1 Step -1
Set wksToDelete = ThisWorkbook.Worksheets(i)
If wksToDelete.Name <> wksToStay.Name Then
Application.DisplayAlerts = False
wksToDelete.Delete
Application.DisplayAlerts = True
End If
Next
End Sub

Test the next code, please:
Sub deleteExceptTheLastSh()
If ActiveWorkbook.Sheets.count > 1 Then
Application.DisplayAlerts = False
ActiveSheet.Delete
Application.DisplayAlerts = True
Else
MsgBox "This is the last sheet and it cannot be deleted!"
End If
End Sub

This happens because you cannot delete the last worksheet in a workbook. Is the macro you have executed with a button? If you do not like the 1004 message, one possible solution may be to create a custom error message:
Sub deleteActiveSheet()
Application.DisplayAlerts = False
On Error GoTo Error
ActiveSheet.Delete
Application.DisplayAlerts = True
Exit Sub
Error:
MsgBox "you cannot delete the last worksheet in the workbook!"
End Sub

If I understand correctly, you don't want to delete the last worksheet, and you want to avoid the error message.
You could try this:
Sub deleteallbutlast()
Application.DisplayAlerts = False
If Worksheets.Count > 1 Then
ActiveSheet.Delete
Else
End
End If
Application.DisplayAlerts = True
End Sub

Related

VBA loop through all worksheets in workbook

I have tried following VBA code, where I want to run this code for all available worksheets in active workbook, I think I am making small mistake and as I am beginner I am not able to find it out, please help to fix it up
Sub ProtectFormulas()
Dim strPassword As String
Dim ws As Worksheet
For Each ws In Sheets
ws.Activate
.Unprotect
.Cells.Locked = False
.Cells.SpecialCells(xlCellTypeFormulas).Locked = True
.Cells.SpecialCells(xlCellTypeFormulas).FormulaHidden = True
.Protect AllowDeletingRows:=True
strPassword = 123456
ActiveSheet.Protect Password:=strPassword
Next ws
End With
End Sub
Any help would be appriciated by word of thanks.
There are 3 issues with your code:
There is no With block.
The following 2 lines will error if there is no formula in one of the sheets:
.Cells.SpecialCells(xlCellTypeFormulas).Locked = True
.Cells.SpecialCells(xlCellTypeFormulas).FormulaHidden = True
Because if there is no formula then .Cells.SpecialCells(xlCellTypeFormulas) is Nothing and therefore nothing has no .Locked and no .FormulaHidden methods.
You mix using Sheets and Worksheets. Note that those are not the same!
Sheets is a collection of all type of sheets (worksheets, chart sheets, etc)
Worksheets is a collection of only type worksheet
If you declare Dim ws As Worksheet and there is for example a chart sheet in your file, then For Each ws In Sheets will error because you try to push a chart sheet into a variable ws that is defined as Worksheet and cannot contain a chart sheet. Be as specific as possible and use Worksheets whenever possible in favour of Sheets.
The following should work:
Option Explicit
'if this is not variable make it a constant and global so you can use it in any procedure
Const strPassword As String = "123456"
Sub ProtectFormulas()
'Dim strPassword As String
'strPassword = "123456" 'remove this here if you made it global
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
With ws
.Activate 'I think this is not needed
.Unprotect Password:=strPassword 'unprotect probably needs your password too or this will not work once the worksheet was protected.
.Cells.Locked = False
Dim FormulaCells As Range
Set FormulaCells = Nothing 'initialize (because we are in a loop!)
On Error Resume Next 'hide error messages (next line throws an error if no forumla is on the worksheet
Set FormulaCells = .Cells.SpecialCells(xlCellTypeFormulas)
On Error Goto 0 ' re-enable error reporting! Otherwise you won't see errors if they occur!
If Not FormulaCells Is Nothing Then 'check if there were formulas to prevent errors if not
FormulaCells.Locked = True
FormulaCells.FormulaHidden = True
End If
.Protect AllowDeletingRows:=True, Password:=strPassword
End With
Next ws
End Sub

Delete worksheets if cells below specified strings are empty

I am trying to write a script which will cycle through the worksheets in my workbook and delete the worksheet if the cells directly under the strings "detected", "not detected" and "other" are empty. If there is something entered under any of the three strings the worksheet shouldn't be deleted.
I have some code (below) which will delete the worksheet if a specific cell is empty, but I need to integrate a piece to FIND any of the three strings (if they are there, they will be in column A), and to offset this to check whether the cell below is empty.
Sub DeleteEmptyWorksheets()
Dim MySheets As Worksheet
Application.DisplayAlerts = False
For Each MySheets In ActiveWorkbook.Worksheets
If MySheets.Range(“A1”) = “” Then
MySheets.Delete
End If
Next
Application.DisplayAlerts = True
End Sub
The script will be used in processing COVID19 test results, so if you can help it will be extra karma points!!
Thankyou.
Here's a code that should assist you.
Sub DeleteEmptyWorksheets()
Dim MySheets As Worksheet
Dim rngTest As Range
Dim arTest
Dim blNBFound As Boolean
arTest = Array("detected", "not detected", "other")
Application.DisplayAlerts = False
For Each MySheets In ActiveWorkbook.Worksheets
blNBFound = False
For i = LBound(arTest) To UBound(arTest)
Set rngTest = MySheets.Range("A:A").Find(arTest(i))
If Not rngTest Is Nothing Then
If Len(rngTest.Offset(1, 0)) > 0 Then
blNBFound = True
Exit For
End If
End If
Next i
If blNBFound = False Then MySheets.Delete
Next
Application.DisplayAlerts = True
End Sub

VBA message automation error element not found

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.)

Excel unable to access file

Just doing something at work, and trying to reference a file on a network directory on VBA.
Sub CostPriceMain()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
NewFile = Application.GetOpenFilename(FileFilter:="Microsoft Excel Files
(*.xlsx; *.xls), (*.xlsx; *.xls), All Files, *.*", FilterIndex:=1)
If NewFile = False Then Exit Sub
If NewFile <> False Then
Set wkbk = Workbooks.Open(NewFile)
End If
Dim Sh As Worksheet
For Each Sh In wkbk.Worksheets
If Sh.Visible = True Then
Sh.Activate
Sh.Cells.Copy
Workbooks("S:\Stafford\WK24 WH.xls").Sheets("Name").Range("A1").PasteSpecial Paste:=xlValues
End If
Next Sh
Application.CutCopyMode = False
ActiveWorkbook.Close True
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Done = MsgBox("Task Complete", vbOKOnly)
End Sub
I'm trying to open it so that that I can paste data from wkbk into it. However I keep getting a 'Microsoft Office Excel cannot access the file' runtime error 1004.
Is this an issue because the file is not stored locally? As I'm scratching my head at this.
Try this:
Sub CostPriceMain()
Dim SourceWkb As Workbook
Dim TargetWkb As Workbook
Dim SourceWksht As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
NewFile = Application.GetOpenFilename(FileFilter:="Microsoft Excel Files (*.xlsx; *.xls), (*.xlsx; *.xls), All Files, *.*", FilterIndex:=1)
If NewFile = False Then Exit Sub
If NewFile <> False Then
Set SourceWkb = Workbooks.Open(NewFile)
End If
Set TargetWkb = Workbooks.Open("S:\Stafford\WK24.xls") ' warning - XLS file could cause problems - see note
For Each SourceWksht In SourceWkb.Worksheets
If SourceWksht.Visible Then
SourceWksht.Copy After:=TargetWkb.Sheets(TargetWkb.Sheets.Count)
End If
Next SourceWksht
TargetWkb.Close True
SourceWkb.Close False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Done = MsgBox("Task Complete", vbOKOnly)
End Sub
I notice your "wk24" is an XLSfile, yet you invite the user to choose XLSor XLSX files to import from. You can't import an XLSX file into an XLS file using this method. I'd suggest changing your target file to WK24.XLSX
You open your workbook within the loop which means it will try and open it for every sheet - and throw an error when it's already open.
Open the workbook before you start looping and then just reference it. This code will copy each visible sheet from the workbook containing the code to WK24.xls (note, no activating of sheets required):
Sub Test()
Dim wrkBk As Workbook
Dim wrkSht As Worksheet
Set wrkBk = Workbooks.Open("S:\Stafford\WK24.xls")
For Each wrkSht In ThisWorkbook.Worksheets
If wrkSht.Visible Then
'Copy sheet.
wrkSht.Copy After:=wrkBk.Sheets(wrkBk.Sheets.Count)
End If
Next wrkSht
End Sub
Edit:
I've made a few changes to your posted code.
I removed If NewFile = False Then Exit Sub - If NewFile isn't false it will run the code, otherwise it jumps straight to the end. It provides a single exit point for your procedure.
I updated ActiveWorkbook.Close True to your referenced workbooks. ActiveWorkbook may not always be the correct book - always best to avoid Active or Select... if you find yourself using either (or Activate or Selected or anything similar) then you're probably making more work for yourself.
Your MsgBox isn't going to act on any response, it's just informing you so no need to set it to a variable.
If you're still finding it says the workbook isn't accessible then triple check the file location, file name, whether it's already open.
Which file is causing the problem? NewFile or WK24?
Also - are you copying the whole sheet, cells from the sheet, copy & pastespecial - you keep changing your code.
Sub CostPriceMain()
Dim NewFile As Variant
Dim wkbk As Workbook
Dim wrkBk As Workbook
Dim wrkSht As Worksheet
NewFile = Application.GetOpenFilename(FileFilter:="Microsoft Excel Files (*.xlsx; *.xls), (*.xlsx; *.xls), All Files, *.*", FilterIndex:=1)
If NewFile <> False Then
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wkbk = Workbooks.Open(NewFile)
Set wrkBk = Workbooks.Open("S:\Stafford\WK24.xls")
For Each wrkSht In wkbk.Worksheets
If wrkSht.Visible Then
'Copy all cells with formula, etc.
'wrkSht.Cells.Copy Destination:=wrkBk.Worksheets("Sheet1").Range("A1")
'Copy and pastespecial all cells.
'wrkSht.Cells.Copy
'wrkBk.Worksheets("Sheet1").Range("A1").PasteSpecial xlPasteValues
'Copy whole sheet to WK2 (Sheets includes ChartSheets)
wrkSht.Copy After:=wrkBk.Sheets(wrkBk.Sheets.Count)
End If
Next wrkSht
wrkBk.Close True 'Closes WK24.
wkbk.Close False 'Closes your chosen file without saving.
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox "Task Complete", vbOKOnly
End If
End Sub

Error selecting cell range

When attempting to clear a cell range in a hidden worksheet I am receiving a "Select method of range class failed error" on line .Range("A1:EC168").select
Below is a copy of my code, thanks for any advice.
Private Sub ClearAll_Click()
Dim Sheet As Worksheet
Dim CompareTool As Workbook
Dim Sheetname As String
Set CompareTool = ThisWorkbook
With Application
.DisplayAlerts = False
.ScreenUpdating = True
End With
For Each Sheet In CompareTool.Worksheets
If Left(Sheet.Name, 8) = "Scenario" Then
Sheetname = Sheet.Name
With CompareTool.Sheets(Sheetname)
.Visible = True
.Range("A1:EC168").Select
.Visible = False
End With
End If
Next Sheet
Unload Me
End Sub
You will not be able to Select anything on an inactive sheet, so the solution would be to Activate it prior to the Select statement, though since the sheet is hidden, I'm not sure what the benefit of making the selection is...
With Sheet
.Visible = True
.Activate
.Range("A1:EC168").Select
.Visible = False
End With
You don't need to select the range to delete it, just do .Range("A1:EC168").Delete. This way, you don't even need to activate or make it visible:
With Sheet
.Range("A1:EC168").Delete
End With

Resources