The print functionality of Excel (using VBA) is extremely slow. I'm hoping someone has a way of speeding the printing up (without using the Excel 4 Macro trick). Here's how I do it now:
Application.ScreenUpdating = False
With ActiveSheet.PageSetup
-various setup statements which I've already minimized-
End With
ActiveSheet.PrintOut
Application.ScreenUpdating = True
Yes, the PageSetup properties are very slow when you set them.
You have already set Application.ScreenUpdating = False, which is good, but an equally (or more) important step in this case is to set Application.Calculation = xlCalculationManual. (It is best if you save these settings and then restore them to the original at the end.)
Additionally, the property get for each PageSetup property is very fast, while it is only the property set that is so slow. Therefore, you should test the new property setting to make sure it isn't already the same as the existing property value in order to prevent an unnecessary (and expensive) call.
With all this in mind, you should be able to use code that looks something like the following:
Dim origScreenUpdating As Boolean
origScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False
Dim origCalcMode As xlCalculation
origCalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
With ActiveSheet.PageSetup
If .PrintHeadings <> False Then .PrintHeadings = False
If .PrintGridlines <> False Then .PrintGridlines = False
If .PrintComments <> xlPrintNoComments Then .PrintComments = xlPrintNoComments
' Etc...
End With
Application.ScreenUpdating = origScreenUpdating
Application.Calculation = origCalcMode
Edit: A couple of updates:
For Excel 2010 and above you can make use of the 'Application.PrintCommunication' property, while for Excel 2007 and below, you can make use of 'ExecuteExcel4Macro'. For more details, see Migrating Excel 4 Macros to VBA.
For Excel 2007 and below, another interesting trick is to temporarily assign the printer driver to the 'Microsoft XPS Document Writer' and then set it back. Printing speed can improve by 3x. See: Slow Excel PageSetup Methods.
Hope this helps...
In furthering Michael's post and answering #rhc's question, the following code may also help you if need to copy Page Setup customizations from a single worksheet to multiple worksheets in a workbook:
Public Sub CopyPageSetupToAll(ByRef SourceSheet As Worksheet)
' Raise error if invalid source sheet is passed to procedure
'
If (SourceSheet Is Nothing) Then
Err.Raise _
Number:=vbErrorObjectVariableNotSet, _
Source:="CopyPageSetupToAll", _
Description:="Unable to copy Page Setup settings: " _
& "invalid reference to source sheet."
Exit Sub
End If
SourceSheet.Activate
With SourceSheet.PageSetup
' ...
' place PageSetup customizations here
' ...
End With
SourceSheet.Parent.Worksheets.Select
Application.SendKeys "{ENTER}", True
Application.Dialogs(xlDialogPageSetup).Show
End Sub
Alternatively, you could also modify the procedure to create a temporary worksheet to host your Page Setup changes, and then propagate those changes out to the other worksheets in your workbook:
Public Sub CopyPageSetupToAll(ByRef SourceBook As Workbook)
Dim tempSheet As Worksheet
' Raise error if invalid workbook is passed to procedure
'
If (SourceBook Is Nothing) Then
Err.Raise _
Number:=vbErrorObjectVariableNotSet, _
Source:="CopyPageSetupToAll", _
Description:="Unable to copy Page Setup settings: " _
& "invalid reference to source workbook."
Exit Sub
End If
Set tempSheet = SourceBook.Worksheets.Add
tempSheet.Activate
With tempSheet.PageSetup
' ...
' place PageSetup customizations here
' ...
End With
SourceBook.Worksheets.Select
Application.SendKeys "{ENTER}", True
Application.Dialogs(xlDialogPageSetup).Show
tempSheet.Delete
Set tempSheet = Nothing
End Sub
Due to the use of the SendKeys() function and Application.Dialogs functionality, this code does not offer the cleanest possible solution. However, it gets the job done. :)
if you want to have basicly the same page settings for every tab in a workbook can you speed things up by setting up one workshet and then copying that worksheet's settings somehow to the other worksheets? Is this possible?
Related
I have a VBA function that will crash excel when I run it ("Microsoft Excel has stopped working"), but works fine if I step through each line in the editor. I want to open another workbook with the function, change the slicers on a given sheet, find a value, and then close the new workbook without saving it. The function I have is as follows:
Function ValueLookup()
Dim Check As Boolean
Dim NewBook As Workbook
Check = IsWorkBookOpen("C:\Location\Filename")
If Check = False Then
Set NewBook = Workbooks.Open("C:\Location\Filename")
Else
Set NewBook = Workbooks("Filename")
End If
NewBook.Activate
Worksheets("Sheetname").Activate
ActiveSheet.PivotTables("pivottable1")ManualUpdate = True
With ActiveWorkbook.SlicerCaches("Slicer_SlicerName")
.ClearManualFilter
.VisibleSlicerItemsList = Array("[Tablename].[Columnname].&[MyValue]")
End With
ActiveSheet.PivotTables("pivottable1").ManualUpdate = False
ValueLookup = ActiveSheet.Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
searchorder:=xlByRows, _
searchdirection:=xlPrevious, _
MatchCase:=False)
If Check = False Then NewBook.Close savechanges:=False
End Function
(IsWorkBookOpen() is taken from Detect whether Excel workbook is already open, and doesn't seem to present any issues).
It seems that trying to close the new workbook is what's causing the issue, and if the workbook is open before I run the function there is no issue. The subroutine that calls the function will normally execute the line after the function right before excel crashes (opening a MsgBox for user input). I have tried adding Sleep 1000 after each line and adding DoEvents after the last line with no change in results. I've tried changing
NewBook.Close savechanges:= False
to
Application.Windows("NewBook").Close
without any difference. I've also tried replacing the end with
If Check = False Then
Cancel = True
Application.OnTime Now, "Close_Xls"
End If
End Function
Sub Close_Xls()
ThisWorkBook.Close savechanges:=False
End Sub
but this closes the wrong workbook (the original one I'd like the macro to be run from) after my subroutine has finished. However, it does seem to execute the code successfully before closing the wrong workbook, and does not cause excel to crash.
Any suggestions?
Edit:
It now appears to work without issues. I changed the following:
If Check = False Then NewBook.Close savechanges:=False
End Function
To
NewBook.Saved = True
If Check = False Then
Cancel = True
Application.OnTime Now, "Close_Xls"
End If
End Function
Sub Close_Xls()
Workbooks("Filename").Close savechanges:=False
End Sub
Thanks!
Changing the Close_Xls() sub to the following will target the correct sheet to close:
Sub Close_Xls()
Workbooks("Filename").Close savechanges:=False
End Sub
Another way to close the workbook without saving that might work is to use:
NewBook.Saved = True
before closing.
I have a workbook I would like to disable the Add New Sheet button that is next to the tabs. I have searched and found the following that disable the insert options on the workbook book which is great.
Application.CommandBars("Ply").FindControl(, 945).Enabled = False
Application.CommandBars("Insert").Controls(4).Enabled = False
But I have yet to find the command for the Add New Sheet button. Is there a place that lists all these options or a tool I can use to identify the control or button.
The workbook is shared so automatically deleting the sheet on creation will not work.
Protect Structure does not work either and throws the following error:
In the ThisWorkbook code sheet, paste the following.
Option Explicit
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Application.DisplayAlerts = False
Sh.Delete
End Sub
Any new (or copied) worksheet that is created is instantly deleted.
This isn't a proper solution to your actual problem, but it will give the illusion of doing what you want...
In the ThisWorkbook module, add this to instantly hide any new sheets with 'DeleteThisSheet' in cell A1
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Sh.Cells(1, 1) = "DeleteThisSheet"
Sh.Visible = xlSheetVeryHidden
End Sub
Obviously, this will clutter up the workbook with hidden sheets, so you can clear them out from time to time using this code to switch off sharing and delete the hidden sheets.
Sub removeSheets()
Dim ws As Worksheet
' Turn off sharing
Application.DisplayAlerts = False
If ActiveWorkbook.MultiUserEditing Then
ActiveWorkbook.ExclusiveAccess
End If
' Delete veryhidden sheets with delete code
For Each ws In ThisWorkbook.Sheets
If ws.Visible = xlSheetVeryHidden And ws.Cells(1, 1) = "DeleteThisSheet" Then
ws.Visible = xlSheetVisible
ws.Delete
End If
Next ws
' Turn sharing back on
If Not ActiveWorkbook.MultiUserEditing Then
ActiveWorkbook.SaveAs ActiveWorkbook.Name, accessmode:=xlShared
End If
Application.DisplayAlerts = True
End Sub
As I say, it's not ideal, but may at least serve your purpose, although probably won't stand up to many people repeatedly attempting to add new sheets. You could possibly add a msgbox to the newssheet code to say something along the lines of 'This action has been disabled' to stop them retrying. I'll keep an eye on this thread to see if anyone comes up with a proper solution, it's always good to learn something new.
Not sure if this solves the issue:
Application.CommandBars("Insert").Controls(4).Visible = False
This uses Visible property.
I'm trying to programmatically copy a large range of cells from one workbook to another in VBA. I want to copy the formatting (including the entire source theme) and values, but NOT formulas. The following is my VBA code:
fromCells.Copy
toCells.PasteSpecial Paste:=xlPasteFormats
toCells.PasteSpecial Paste:=xlPasteColumnWidths
toCells.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
Unfortunately, there are occasions when the above code doesn't work. This is usually with Font face and size. I noticed that whenever this happens, the only way to copy the font formatting across is to use xlPasteAllUsingSourceTheme, so it seems the font formatting is somehow registered to a 'source theme'. Unfortunately, xlPasteAllUsingSourceTheme doesn't work for me because it's copying formulas as well.
So is there a way to copy the source theme (formatting only) across? Or maybe a way to force copy all the font formatting across?
Note: Copying using xlPasteAllUsingSourceTheme and then overwriting it with xlPasteValues won't work for me because when the formulas is copied it keeps popping up message boxes telling me about issues with the formulas (such as conflicting named ranges used in the formulas, etc.).
I'm using Excel 2013. I noticed this problem doesn't seem to arise in Excel 2007 or earlier. Any help is appreciated.
Edit: I've also tried the following code (added to the beginning of the above code), it still doesn't work...
Dim themeTempFilePath As String
themeTempFilePath = Environ("temp") & "\" & fromWorkbook.Name & "Theme.xml"
fromWorkbook.Theme.ThemeFontScheme.Save themeTempFilePath
toWorkbook.Theme.ThemeFontScheme.Load themeTempFilePath
fromWorkbook.Theme.ThemeColorScheme.Save themeTempFilePath
toWorkbook.Theme.ThemeColorScheme.Load themeTempFilePath
Update: It seems the above code for saving and loading themes does work. The problematic text that I was looking at came from a different place - a form control. It was copied as a picture (using Shape.CopyPicture) but somehow the font gets changed in the process. However, I'll post this issue as another question.
For this question, I'll put up the theme saving and loading mechanism as an answer.
Try 1 or 2
Option Explicit
Public Sub copyWithoutFormulas_1()
xlEnabled False
With Sheet2
.EnableCalculation = False
.EnableFormatConditionsCalculation = False
.UsedRange.EntireColumn.Delete
Sheet1.UsedRange.Copy .Cells(1, 1)
.UsedRange.Value2 = .UsedRange.Value2
.EnableCalculation = True
.EnableFormatConditionsCalculation = True
End With
Application.CutCopyMode = False
xlEnabled True
End Sub
Public Sub copyWithoutFormulas_2()
xlEnabled False
Sheet1.Copy After:=Worksheets(Worksheets.Count)
With Worksheets(Worksheets.Count).UsedRange
.Value2 = .Value2
End With
xlEnabled True
End Sub
Private Sub xlEnabled(ByVal opt As Boolean)
With Application
.EnableEvents = opt
.DisplayAlerts = opt
.ScreenUpdating = opt
.Calculation = IIf(opt, xlCalculationAutomatic, xlCalculationManual)
End With
End Sub
To force copy the source theme to the destination cells, one can do the following. Unfortunately, this method will apply the source theme to the entire destination workbook, which is OK in my situation. Not sure if it's useful for anyone else.
Sub CopyText(fromCells As Range, toCells As Range, Optional copyTheme As Boolean = False)
If copyTheme Then
Dim fromWorkbook As Workbook
Dim toWorkbook As Workbook
Dim themeTempFilePath As String
Set fromWorkbook = fromCells.Worksheet.Parent
Set toWorkbook = toCells.Worksheet.Parent
themeTempFilePath = Environ("temp") & "\" & fromWorkbook.Name & "Theme.xml"
fromWorkbook.Theme.ThemeFontScheme.Save themeTempFilePath
toWorkbook.Theme.ThemeFontScheme.Load themeTempFilePath
fromWorkbook.Theme.ThemeColorScheme.Save themeTempFilePath
toWorkbook.Theme.ThemeColorScheme.Load themeTempFilePath
End If
Set toCells = toCells.Cells(1, 1).Resize(fromCells.Rows.Count, fromCells.Columns.Count)
fromCells.Copy
toCells.PasteSpecial Paste:=xlPasteFormats
toCells.PasteSpecial Paste:=xlPasteColumnWidths
toCells.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End Sub
I have used this site quite a bit but this is the first question i have posted, hopefully I can give enough detail. I cannot find any relevant answers because no matter what i search, I get various answers relating to looping code.
Some background:
I have designed an excel document to track some items in my workplace (hereafter referred to as Master Document). As the previous tracker allowed users to edit anything at any time, I have used forms to ensure all information is entered correctly and stored securely. For each item in the Master Document there is a separate excel workbook (hereafter referred to as Item Document).
There are a number of sheets in the Master Document which run code everytime they are activated (because they need to update).
As there is some VBA code in every Item Document which is crucial in syncing data with the Master Document, I have added a Warning worksheet which is shown when the Item Document is opened without macros. This involved using the workbook open, before save and after save events to ensure only the Warning is shown without macros. Here is the code for each event (placed in ThisWorkbook Module obviously)
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Auto_Open
'This is for sync (Master Document checks for text file to see if any changes have been made to Item Document)
If booChange = True Then
Dim oFile As Object
Set oFile = fso.CreateTextFile(strTextFile)
SetAttr strTextFile, vbHidden
booChange = False
End If
'Turn off Screen Updating
Application.ScreenUpdating = False
'Show warning sheet
Sheets("Warning").Visible = xlSheetVisible
'Hide all sheets but Warning sheet
For Each sh In ThisWorkbook.Worksheets
If Not sh.Name = "Warning" Then sh.Visible = xlVeryHidden
Next sh
End Sub
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
'Show all sheets
For Each sh In ThisWorkbook.Worksheets
sh.Visible = xlSheetVisible
Next sh
'Hide the warning sheet
Sheets("Warning").Visible = xlVeryHidden
'Return focus to the main page
ThisWorkbook.Worksheets(1).Activate
'Turn on Screen Updating
Application.ScreenUpdating = True
ThisWorkbook.Saved = True
End Sub
Private Sub Workbook_Open()
'Turn off Screen Updating
Application.ScreenUpdating = False
'Show all sheets
For Each sh In ThisWorkbook.Worksheets
sh.Visible = xlSheetVisible
Next sh
'Hide the warning sheet
Sheets("Warning").Visible = xlVeryHidden
'Return focus to the main page
ThisWorkbook.Worksheets(1).Activate
'Turn on Screen Updating
Application.ScreenUpdating = True
ThisWorkbook.Saved = True
End Sub
And just for completeness, here is all code in Module1 of Item Document
'Declarations
'Strings
Public strSourceFolder As String
Public strTextFile As String
'Other
Public fso As FileSystemObject
Public booChange As Boolean
Public wsFlow As Worksheet
'Constants
Public Const strURNSheetName = "Part 1 Plant Flow Out Summ"
Sub Auto_Open()
Set fso = CreateObject("Scripting.FileSystemObject")
Set wsFlow = ThisWorkbook.Worksheets(strURNSheetName)
strSourceFolder = fso.Getfile(ThisWorkbook.FullName).ParentFolder.Path
strTextFile = fso.BuildPath(strSourceFolder, ThisWorkbook.Worksheets(strURNSheetName).Range("W2").Value & ".txt")
End Sub
When an item is created in the Master Document using the 'frmNewEntry' form the info is checked and entered into the Master Document then a template Item Document is opened and saved with a new unique filename. It is then unprotected, updated with the new information, protected, saved and closed. The Master Document is then saved. Code follows (edited to omit lengthy formatting and data entry):
Form Code:
Private Sub btnSave_Click()
'Values on form are verified
'Master Document sheet is unprotected, formatted and data entry occurs
'Clear Userform and close
For Each C In frmNewEntry.Controls
If TypeOf C Is MSForms.ComboBox Then
C.ListIndex = -1
ElseIf TypeOf C Is MSForms.TextBox Then
C.Text = ""
ElseIf TypeOf C Is MSForms.CheckBox Then
C.Value = False
End If
Next
frmNewEntry.Hide
'Create filepaths
Create_Filepath
'Some hyperlinks are added and the Master Document worksheet is protected again
'Create Flowout Summary
Create_Flowout_Summary
'Update Flowout Summary
Update_Flowout_Summary
'Turn on screen updating
Application.ScreenUpdating = True
'Update Activity Log
Update_Log ("New: " & strNewURN)
Debug.Print "Before Save Master"
'Save tracker
ThisWorkbook.Save
Debug.Print "After Save Master"
End Sub
Module1 Code:
Public Sub Create_Flowout_Summary()
'Create a new flowout summary from the template
'Turn off screen updating
Application.ScreenUpdating = False
'Check if workbook is already open
If Not Is_Book_Open(strTemplate) Then
Application.Workbooks.Open (strTemplatePath)
End If
Debug.Print "Before SaveAs Create"
'Save as new flowout summary
Application.Workbooks(strTemplate).SaveAs fileName:=strFilePath
Debug.Print "After SaveAs Create"
'Close Document Information Panel
ActiveWorkbook.Application.DisplayDocumentInformationPanel = False 'Doesn't seem to work
'Turn on screen updating
Application.ScreenUpdating = True
End Sub
Public Sub Update_Flowout_Summary()
'Update the flowout summary for current call
Dim wsURN As Worksheet
Set wsURN = Workbooks(strFileName).Worksheets(strWsURNName)
'Unprotect Flowout Summary worksheet
wsURN.Unprotect "Flowout Summary"
'Write values to flowout summary
'Protect Flowout Summary worksheet
wsURN.Protect "Flowout Summary", False, True, True, True, True
Debug.Print "Before Save Update"
'Save flowout summary
Application.Workbooks(strFileName).Save
Debug.Print "After Save Update"
'Close Document Information Panel
ActiveWorkbook.Application.DisplayDocumentInformationPanel = False
'Turn on screen updating
Application.ScreenUpdating = True
End Sub
Problem detail:
When I create a new entry it is taking a very long time, I accidentally discovered that the Master Document is running the code in every sheet activate event (mentioned above) (I had a diagnostic msgbox in one of the sheets which mysteriously appeared when i created a new entry)
I have therefore drawn the conclusion that the code is somehow activating every worksheet but have no idea why....
Any help will be much appreciated, and if i have missed anything out that may help in diagnosing just let me know.
EDIT: The other strange phenomenon is that this does not happen when I try to step through the code to find exactly where the activate events are being triggered.
EDIT: Code in the worksheet activate event
Private Sub Worksheet_Activate()
'Turn off Screen Updating
Application.ScreenUpdating = False
'Simply writes data to the sheet (excluded because it is lengthy)
'Turn on Screen Updating
Application.ScreenUpdating = True
wsMyCalls.Protect Password:=strPassword
Debug.Print "wsMyCalls"
MsgBox "This sheet uses your username to display any calls you own." & vbNewLine & _
"It relies on the correct CDSID being entered for owner." & vbNewLine & vbNewLine & _
"Regards" & vbNewLine & _
"Your friendly spreadsheet administrator", vbOKOnly, "Information"
End Sub
EDIT: I added some Debug.Prints to the code (above) and this is what i got.
Before SaveAs Create
After SaveAs Create
Before Save Update
After Save Update
Before Save Master
After Save Master
wsMyCalls
This shows that the code is executing between Debug.Print "After Save Master" and an End Sub. There is no code in there???
Thanks
I believe we aren't seeing your whole code on here. It is difficult to diagnose considering we don't have the workbook to debug ourselves. However I have a similar 'welcome' page that is displayed every time one of my workbooks opens to ask the user to activate macroes. I DO put EnableEvents to false and put my sheet in a certain state before saving, and placing it back after saving.
I will show you exactly how I do it because I have a feeling your problem is related to not disabling EnableEvents are the right timings. I am unsure how to time it based on how your workbook functions because of the mentioned incomplete code.
The sheet is called f_macros. Here is it's worksheet activate event that prevents further navigation:
Private Sub Worksheet_Activate()
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayWorkbookTabs = False
End Sub
In my Workbook_BeforeSave:
I record the current state of DisplayHeadings and such at first:
Dim Displaytabs As Boolean
Dim DisplayHeadings As Boolean
Dim menu As CommandBar
Dim ligne As CommandBarControl
Displaytabs = ActiveWindow.DisplayWorkbookTabs
DisplayHeadings = ActiveWindow.DisplayHeadings
I then reset my custom right click, turn off EnableEvents and screen updating. I set DisplayWorkbookTabs to false for good measure.
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.CommandBars("Cell").reset
ActiveWindow.DisplayWorkbookTabs = False
Then I run Cacherdata (HideData, sub in another module that is annexed underneath) I save, and i run the sub macro_activees to put the workbook back in working order for the user. I turn EnableEvents back on, and put the headings back to how they were:
m_protection.Cacherdata
ThisWorkbook.Save
m_protection.macro_activees
Application.ScreenUpdating = True
Application.enableevents = True
ActiveWindow.DisplayWorkbookTabs = Displaytabs
ActiveWindow.DisplayHeadings = DisplayHeadings
I cancel the ordinary Save (important!) and indicate the workbook is saved so they can exit normally without being prompted to save.
Cancel = True
ThisWorkbook.Saved = True
In the BeforeClose, it checks whether or not the workbook state is Saved. if yes, it quits. If not, it does a similar procedure:
If Not (ThisWorkbook.Saved) Then
rep = MsgBox(Prompt:="Save changes before exiting?", _
Title:="---", _
Buttons:=vbYesNoCancel)
Select Case rep
Case vbYes
Application.ScreenUpdating = False
Application.enableevents = False
ActiveWindow.DisplayHeadings = True
m_protection.Cacherdata
ThisWorkbook.Save
Case vbCancel
Cancel = True
Exit Sub
End Select
End If
The workbook open event checks whether it is read-only mode, but that's all. I don't have a Workbook AfterSave.
Annex
CacherData makes every sheet VeryHidden so the user doesn't f*** up the data without activating macros. It records the current active sheet so the user goes back to where they were, unprotects the workbook, hides sheets, protects it back and that's all:
Sub Cacherdata()
Dim ws As Worksheet
f_param.Range("page_active") = ActiveSheet.Name
f_macros.Activate
ThisWorkbook.Unprotect "-----"
For Each ws In ThisWorkbook.Worksheets
If ws.CodeName <> "f_macros" Then ws.visible = xlSheetVeryHidden
Next
ThisWorkbook.Protect "-----"
Exit Sub
End Sub
macros_activees does the opposite:
Sub macro_activees()
Dim ws As Worksheet
ThisWorkbook.Unprotect "-----"
For Each ws In ThisWorkbook.Worksheets
ws.visible = xlSheetVisible
Next
ThisWorkbook.Sheets(f_param.Range("page_active").Value).Activate
ThisWorkbook.Unprotect "-----"
'it unportects twice because of the activate event of the worksheet, don't mind that
Exit Sub
End Sub
Error handling was removed because it was useless to show, but everything else should be there.
EDIT: If this doesn't help you at all, maybe your problem is because the workbooks you create have code in them 9from what i gather) that can affect how long it takes to run your code? If they have an Open procedure themselves, could that be it?
I am trying to delete a worksheet when the user click's on an image (button) in Excel. However this makes excel crash and restart, forgetting any unsaved progress.
This is my sub:
Sub DeletePlan()
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
Dim SheetNamesToCopy As String
SheetNamesToCopy = ActiveSheet.Name
' Check what addon sheets exists for the media, then add existing ones to string
If CheckSheet("periodeplan", True) = True Then
ThisWorkbook.SheetS(SheetNamesToCopy & " - periodeplan").Delete
End If
If CheckSheet("ukesplan", True) = True Then
ThisWorkbook.SheetS(SheetNamesToCopy & " - ukesplan").Delete
End If
If CheckSheet("Input", True) = True Then
ThisWorkbook.SheetS(SheetNamesToCopy & " - Input").Delete
End If
SheetS("Totalplan").Select
ThisWorkbook.SheetS(SheetNamesToCopy).Delete
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
End Sub
The application crashes most of the time. But not always... Any ideas what might be wrong?
(I have tested and confirmed that the delete function causes the crash, but its not always the same sheet).
Edit: This function is not deleting the last sheet in the workbook. There are 20 more sheets. Also i use Application.Calculation = xlCalculationAutomatic, because there are allot of formulas, and i do not want excel to calculate changes before all is connected sheets are deleted.
Any hint or answer is appreciated :)
The error occurs when the button that initiates the macro is located on one of the sheets that are to be deleted.
So the answer is: Do not create a button (or image linked to a macro) that deletes the sheet it is on.
If anybody can add to this answer with a reason for this error, please do so ;)
I just ran into this problem myself! I'm going to defer to more experienced designers on a way to refine this technique, but as a general concept, I do have a working solution:
If you allow the macro to run it's course and then delete the sheet, it doesn't crash. Something like this:
Sub Delete_This_Sheet()
Application.OnTime Now + TimeValue("00:00:02"), "Watergate"
Sheets("Sheet with a death sentence").Visible = False
End Sub
Sub Watergate() 'To make things go away
Application.DisplayAlerts = False
Sheets("Sheet with a death sentence").Delete
Application.DisplayAlerts = True
End Sub
Resurrecting this thread because I had the same issue and want to share the solution.
I had a very simple sub to delete worksheets:
Sub deletetraindoc()
Dim ws As Worksheet
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Sheets
'This if statement looks for any worksheet that contains the term "Form"
'Any worksheet that contains that string will be deleted
If InStr(ws.Name, "Form") > 0 Then
Application.DisplayAlerts = False 'Deactivates the standard deletion confirmation
ws.Activate
ws.Delete 'Deletes the worksheet
Application.DisplayAlerts = True 'Reactivates display alerts
End If
Next
Application.ScreenUpdating = True
End Sub
This inconsistently caused crashing until I added the line "ws.Activate" to activate each worksheet before deleting, which seems to have resolved the issue. I've run into this problem in many other situations performing actions on worksheets, but it usually would result in an object error instead of a complete crash.
I found that in Office 2013, you cannot place a button that overlaps a cell that that macro changes. Interesting enough, it doesn't occur if the change is numeric in nature, but if it is alphanumeric, it blows up excel when you attempt to delete that tab. Turns out, it blows it up when attempting to delete the tab manually (by mouse click) or by the macro attempting to do it. THUS, my lesson learned from this thread and applying it to my specific situation is to never place a development button over the cell it changes (in my case, it was simply a cell that gives the status of what that macro was doing). Excel 2013 does not like that situation while Excel 2010 simply didn't care.
I do believe you nare right and the only way around this is to ensure this macro is on the total plan sheet. Also you're doing a few unnecessary steps and the select a sheet should be to activate and select a cell.
Sub DeletePlan()
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
Dim SheetNamesToCopy As String
SheetNamesToCopy = ActiveSheet.Name
'dont delete total plan
If sheetnames = "Totalplan" then exit sub
SheetS("Totalplan").Activate
Activesheet.Cells(1,1).select
'Turn off errors if sheet doesn't exist
On error resume next
ThisWorkbook.SheetS(SheetNamesToCopy & " - periodeplan").Delete
ThisWorkbook.SheetS(SheetNamesToCopy & " - ukesplan").Delete
ThisWorkbook.SheetS(SheetNamesToCopy & " - Input").Delete
ThisWorkbook.SheetS(SheetNamesToCopy).Delete
On error goto 0
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
End Sub
You can delete the active sheet from a button (or image) on the active sheet. You just have to work around it.
ActiveSheet.Move before:=Worksheets(1)
Worksheets(2).Activate
Worksheets(1).Delete
I had a similar, but not identical problem. I had a macro that deleted all the chart sheets with the following command, but although it operated correctly, Excel 2013 was doomed to fail as soon as I tried to save the file, and would "recover" by reverting to the previously saved situation, throwing away any subsequent work:
Oh, and it worked fine until I moved from, I think it was, Excel 2010 to 2013, changing to Windows 10 at the same time.
The command of doom was:
ThisWorkbook.Charts.Delete
Thanks to some inspiration from the answers above, I first inserted a save before the deletion action and then changed the delete as follows (it turned out the saves were not after all needed but I like to have them there, even if I comment them out):
Dim graphSheet As Chart
ActiveWorkbook.Save
For Each graphSheet in this Workbook.Charts
graphSheet.Delete
ActiveWorkbook.Save
Next graphSheet
I should also mention that there is a preceeding Application.DisplayAlerts = False before the for loop and of course the Application.DisplayAlerts = True after the Next... statement to cut out the unwanted
are you sure you want to do this type question?
Again, thanks to your contributors for the inspiration.
I wanted a button that would delete a sheet, as the workbook was protected and could 'export' results but couldn't delete unwanted results.
My simple workaround was to have the macro hide the sheet, but then to delete the last hidden sheet, so the files dont become huge with dozens of hidden sheets.
I created a range in a hidden sheet called "DeleteSheet", to store the name of the hidden sheet.
Sub Delete_Sheet()
ActiveWorkbook.Unprotect Password:="Patrick2017"
ActiveSheet.Unprotect Password:="Patrick2017"
On Error Resume Next
' (In event there is no hidden sheet or the sheet is already deleted, resume next)
'The below finds the name of the previously hidden sheet to delete, and stores it.
Dim DeleteSheet As String
DeleteSheet = Range("DeleteSheet")
'The below is to avoid the main sheet being deleted
If ActiveSheet.Name = "POAL Calculator" Then
Exit Sub
End If
' The below stores the current sheets name before hiding, for deleting next time the
' macro is run
Range("DeleteSheet") = ActiveSheet.Name
ActiveWindow.SelectedSheets.Visible = False
' The below deletes the sheet previously hidden
Application.DisplayAlerts = False
Sheets(DeleteSheet).Delete
ActiveWorkbook.Protect Password:="Patrick2017"
Application.DisplayAlerts = True
End Sub
How about moving the button code to a module?
I have had an issue with that in Excel 2016 whereby Option explicit didn't work if the code was in a module, but if the code is in a module, then you 'should' be able to delete the sheet where the button was.