I am looking to create a macro where I take what I have in a master file that is constantly being updating on the last row and placing this into a separate log file.
I would only like to copy specific cells from the last row of the original and paste them into the log file, i've gotten close I believe but need help with the following areas:
Selection of the specific columns in the last row
How to not have the log file open or activated at any point for this to happen when the Macro is run.
I apologize if this question has been answered but I can't seem to curate all the information I am finding online to an applicable solution. Here is the macro I have thus far...
' copy2 Macro
'
Range("B5000").End(xlUp).Select
Selection.EntireRow.copy
Windows("Daily Referral Log.xlsx").Activate
Range("A65536").End(xlUp).Offset(1, 0).Select
ActiveSheet.Paste
End Sub
Looks like you're trying to open the log workbook and paste the last row from a data file into it.
I think this is what you're looking for.
Please let me know if you need something else.
How to not have the log file open or activated at any point for this to happen when the Macro is run.
Regarding this line, I think I am understanding you right.
You don't want to have to open it yourself manually; you want the code to do it.
If that's not what you mean, please let me know (you will have to lock the file for write access to modify it regardless).
Sub CopyLastRowToLog()
Dim ThisWb, wb As Workbook
Set ThisWb = ThisWorkbook
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.ScreenUpdating = False
On Error Resume Next
Set wb = Workbooks.Open("FileName and Path Goes Here") 'Edit This Line
On Error GoTo 0
'Basic Error Handling - Probably worth adding ReadOnly check but keeping code short
If wb Is Nothing Then
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
MsgBox ("Error Opening File")
Exit Sub
End If
'Put the names of the sheets you're using below.
'The first 2 sheets should be the sheet you're copying from
'The second 2 sheets should be the sheet you're copying to
ThisWb.Sheets("Sheet1").Range("A" & Sheets("Sheet1").UsedRange.Rows.Count).EntireRow.Copy _
wb.Sheets("Sheet1").Range("A" & Sheets("Sheet1").UsedRange.Rows.Count + 1)
wb.Close (True)
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Edit:
To answer your first question, the file name looks weird:
Workbooks.Open("C:\Users\EYousefi\Desktop[Daily Referral Log.xlsx]Sheet1")
It should probably be:
Workbooks.Open("C:\Users\EYousefi\Desktop\Daily Referral Log.xlsx")
You don't need to specify the sheet there.
Secondly, to copy specific columns, you would want to change the copy line.
I added 2 new variables to make it easier to read:
'Get the last rows for the workbooks
Dim ThisWBLR, FinalWBLR
ThisWBLR = ThisWB.Sheets("Sheet5").UsedRange.Rows.Count
FinalWBLR = wb.Sheets("Sheet1").UsedRange.Rows.Count+1
ThisWb.Sheets("Sheet5").Range("B" & ThisWBLR & ":D" & ThisWBLR).Copy _
wb.Sheets("Sheet1").Range("B" & FinalWBLR)
You can also specify individual pieces of data one at a time if it is easier for you:
'Copy B to B
ThisWB.Sheets("Sheet5").Range("B" & ThisWBLR).Copy wb.Sheets("Sheet1").Range("B" & FinalWBLR)
'Copy C to C
ThisWB.Sheets("Sheet5").Range("C" & ThisWBLR).Copy wb.Sheets("Sheet1").Range("C" & FinalWBLR)
Related
I have code that copies a range from a sheet in one workbook and pastes it in a sheet in another workbook. The range includes merged cells (I didn't design it). The range it pastes the data is formatted exactly the same as where it is copied from. I tested the VBA by copying it to blank workbooks, and it works. However, when I try to copy it to a the worksheet that already has that same formatting, it gives the “This operation requires the merged cells to be identically sized.” error, and I'm unsure how to get around this. Here is what I have:
Sub testcopying()
Dim FileNm As Object, Cnt As Integer
Dim TargetFiles As FileDialog
Set TargetFiles = Application.FileDialog(msoFileDialogOpen)
With TargetFiles
.AllowMultiSelect = True
.Title = "Multi-select target data files:"
.ButtonName = ""
.Filters.Clear
.Filters.Add "*.xls* files", "*.xls*"
.Show
End With
If TargetFiles.SelectedItems.Count = 0 Then
MsgBox "PICK A FILE!"
Exit Sub
End If
'On Error GoTo below
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Cnt = 1 To TargetFiles.SelectedItems.Count
'open the file and assign the workbook/worksheet
Set FileNm = Workbooks.Open(TargetFiles.SelectedItems(Cnt))
ThisWorkbook.Sheets("Vendor Data Sheets").Range("A1:AJ191").Copy
Workbooks(FileNm.Name).Sheets("Sheet1").Range("A1").PasteSpecial xlPasteValues
Application.CutCopyMode = False
Workbooks(FileNm.Name).Close SaveChanges:=True
Next Cnt
below:
Application.DisplayAlerts = True
Application.ScreenUpdating = True
If Err.Number <> 0 Then MsgBox "File Error"
End Sub
Any thoughts? I think I may have to write it so it unmerges every cell before pasting the data, then re-merges it, as it was able to successfully paste in the blank workbook (with no merging). But with hundreds of different merged cells, that would take a bit to type up, so I'm hoping there are easier answers. Thanks.
The problem is here xlPasteValues- you cannot paste only values because you are copying also formats (merged cells)
If it's not essential for you to keep the formatting ( as you said those are the same in all workbooks) you can just remove xlPasteValues from your code.
Reason #1 of many: It is very possible you accidentally have selected two worksheets before making the change as I have done in my case.
I am new to VBA programming. I want to import the entire row/(s)(example range from column "A" to "BT")that contains only current (today's) date (example, date is in column "B5") from a source excel sheet into current(backup excel)excel sheet automatically without opening the source excel.So, that I can backup my data regularly at the end of the day from backup excel file.
Actually, the source worksheet is being updated regularly and in a day I have 5-10 new rows with the same date(current/today's) and so I want to copy all the new data(s) to backup excel sheet in rows next to previous day's backup in a backup excel file every day.
Thank you
The below VBA code seems working but it is copying the only column of interest but I need the entire rows to be copied. Do you have any idea to modify the below VBA code so that, it will also copy entire rows?
Option Explicit
Private Sub Workbook_Open()
Call ReadDataFromCloseFile
End Sub
Sub ReadDataFromCloseFile()
On Error GoTo ErrHandler
Application.ScreenUpdating = False
Dim src As Workbook
' OPEN THE SOURCE EXCEL WORKBOOK IN "READ ONLY MODE".
Set src = Workbooks.Open("C:\Users\HAMENDRA\Desktop\Equation\Otarry.xlsm", True, True)
' GET THE TOTAL ROWS FROM THE SOURCE WORKBOOK.
Dim iTotalRows As Integer
iTotalRows = src.Worksheets("Records").Range("B1:B" & Cells(Rows.Count, "B").End(xlUp).Row).Rows.Count
' COPY DATA FROM SOURCE (CLOSE WORKGROUP) TO THE DESTINATION WORKBOOK.
Dim iCnt As Integer ' COUNTER.
For iCnt = 1 To iTotalRows
Worksheets("Sheet1").Range("B" & iCnt).Formula = src.Worksheets("Records").Range("B" & iCnt).Formula
Next iCnt
' CLOSE THE SOURCE FILE.
src.Close False ' FALSE - DON'T SAVE THE SOURCE FILE.
Set src = Nothing
ErrHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Replace:
Worksheets("Sheet1").Range("B" & iCnt).Formula = src.Worksheets("Records").Range("B" & iCnt).Formula
With:
Worksheets("Sheet1").Range("B" & iCnt).EntireRow.Formula = src.Worksheets("Records").Range("B" & iCnt).EntireRow.Formula
But, you should also edit the title of this post. As the previous commentor said, you are opening the workbook. I'd suggest something like "How to copy entire row using VBA". Of course, if you had just googled "How to copy entire row VBA," you probably would have found the answer. :-)
Context
I've built a model in Excel which allows users to load budgets and pay data from a download from a pay system. The users can load a cost centres budget (in the I_Budget sheet) adjust it, press save and the data is dumped into a 'SavedData' sheet. Whereby they can then load another cost centre into I_Budget.
However if the user makes a mistake or wishes to revise their previously edited budgets in SavedData they can click 'Load' in I_Budget and the data will be copied across.
VBA Code
The code to load the users budgets from SavedData:
Public Sub LoadUsersSavedBudgets()
Const WORKSHEET_DATA = "SavedData"
Const WORKSHEET_BUDGET = "I_Budget"
Const START_CELL = "A2"
Const END_COLUMN = "H"
' Check if the user can perform the load action
If IsEmpty(Sheets(WORKSHEET_DATA).Range("A2").Value) Then Exit Sub
Worksheets(WORKSHEET_BUDGET).Unprotect
' A fudge to make Excel copy the data in the sheet
Worksheets(WORKSHEET_DATA).Visible = True
' Select all rows in the selection
Call DynamicColumnSelector(WORKSHEET_DATA, START_CELL, END_COLUMN)
' Set the range of the selected cells
Set Rng = Application.Selection
' Copy the selection
Rng.Copy
' Now paste the results
With Sheets(WORKSHEET_BUDGET).Range("A18")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
Worksheets(WORKSHEET_BUDGET).Protect
' Clear the data in I_Budget to give the user a blank canvas
Call DeleteUsersSavedBudgets
Worksheets(WORKSHEET_DATA).Visible = False
Application.ScreenUpdating = True
Sheets(WORKSHEET_BUDGET).Select
MsgBox "Success! Your budgets have been loaded."
End Sub
The code to save the users budgets into SavedData:
Public Sub SaveUsersBudgetAdjustments()
Const WORKSHEET_BUDGET = "I_Budget"
Const START_CELL = "A18"
Const END_COLUMN = "H"
Const WORKSHEET_OUTPUT = "SavedData"
Const FILTER_COST_CENTRE = "I_Setup!I16"
Dim nRng As Range
' Protect user from running this method if no data has been laoded
If IsEmpty(Range("I_Budget!H18").Value) = True Then Exit Sub
' Issue warning to user
If MsgBox("Would you like so save your changes into the O_Budget sheet?" & vbNewLine & vbNewLine & "You can always load them again for editing.", vbYesNo) = vbNo Then Exit Sub
Application.ScreenUpdating = False
' We make sure the budget adjustments have been taken into account before any saving begins
Call UpdateRevisedBudget
Worksheets(WORKSHEET_BUDGET).Unprotect
' Select all rows in the selection
Call DynamicColumnSelector(WORKSHEET_BUDGET, START_CELL, END_COLUMN)
' Set the range of the selected cells
Set Rng = Application.Selection
' Delete the destination contents
'Sheets(WORKSHEET_OUTPUT).Rows("2:" & Rows.Count).Clear
' Copy and paste the selection into the destination sheet
Rng.Copy
' A fudge to allow the copying and pasting of data to work
If IsEmpty(Sheets(WORKSHEET_OUTPUT).Range("A2").Value) Then
With Sheets(WORKSHEET_OUTPUT).Range("A2")
.PasteSpecial xlPasteValues
End With
Else
With Sheets(WORKSHEET_OUTPUT).Range("A1").End(xlDown).Rows.Offset(1, 0)
.PasteSpecial xlPasteValues
End With
End If
' and clear the selection contents
Selection.ClearContents
Worksheets(WORKSHEET_BUDGET).Protect
Application.ScreenUpdating = True
End Sub
Perhaps of most interest is the method I call to dynamically select data down to the last row:
Private Sub DynamicColumnSelector(shtValue, StartCellValue, StartColumnValue)
'Best used when column length is static
Dim sht As Worksheet
Dim LastRow As Long
Dim StartCell As Range
Set sht = Worksheets(shtValue)
Set StartCell = Range(StartCellValue)
'Refresh UsedRange
Worksheets(shtValue).UsedRange
'Find Last Row
LastRow = sht.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'Select Range
Sheets(shtValue).Select
sht.Range(StartCellValue & ":" & StartColumnValue & LastRow).Select
End Sub
The Exam Question
My question is that whilst the above works, it feels smelly and inefficient. Is there a better way I can select data in the sheets and copy it across? I have to take into account the last row within the SavedData sheet as we may be continually adding data to it.
Finding the last row number should work this way (which is not really shorter, only a little bit simpler):
sht.Cells.SpecialCells(xlCellTypeLastCell).Row
In your case, this should yield the same result as sht.Cells.Find, since you accessed UsedRange before. However, the Find operation should deliver the last nonempty row even if you do not access UsedRange before, where the SpecialCellssolution might return a row number which is actually bigger, because the user filled some values there, deleted the values and did not save the document before.
Moreover, I would avoid to call a sub which selects a range which is then grabbed by the next function by Application.Selection. Better, make DynamicColumnSelector a function returning the Range in stake:
Function DynamicColumnSelector(...) as Range
' ...
Set DynamicColumnSelector=sht.Range(...)
End Function
and call it like this
Set Rng = DynamicColumnSelector(...)
Rng.Copy
This makes your code much more robust against later changes. Code which changes or relies on the global selection is error prone when you have to change the order of execution later, or insert some additional code in between. Worse, it is longer, slower and has visual effects to the user. Code which passes the range objects directly does not have these problems.
Unfortunately, the PasteSpecial operations are only available in conjunction with the clipboard, not directly for a range-to-range copy. If you going to copy just values, you do not need PasteSpecial, but if you want to copy formats as wll, this is probably the easiest and most secure solution. So I would not expect that there is a much simpler solution for copy/pasting than the one you found by yourself.
As you asked: copying just values without any formats, without the clipboard:
Set rng = DynamicColumnSelector(...)
Set destinationRng = Sheets(WORKSHEET_OUTPUT).Range("A2")
rng.Copy destinationRng
does it.
I have an advanced filter which pulls data out of a separate workbook (opened earlier on) using defined ranges (which are visible in name manager across all sheets). After i have the data I then want to be able to save a copy of the workbook for reference.
Range("stresslist").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:= _
Range("stressfind"), CopyToRange:=Range("stressout"), Unique:=True
This worked fine before Christmas but now all of the copies give "runtime error 1004 method 'range' of object '_global' failed" which i've narrowed down to
Range("stresslist")
which is the range on another workbook consisting of 3 columns.
does anyone know why it's only failing in the copy, or a way I can make it work in both the copy and the original?
Thanks
Matt
Entire code
Sub findstress()
datafile = "Datafile.xlsx"
calcfile = ThisWorkbook.Name
dataopen = False
frontend = ActiveSheet.Name
Application.DisplayAlerts = False
'Application.ScreenUpdating = False
'Open Data workbook
On Error Resume Next
Workbooks(datafile).Activate
If Err.Number <> 0 Then
Err.Clear
Application.Workbooks.Open ThisWorkbook.Path & "\" & datafile
If Err.Number <> 0 Then
Err.Clear
Application.Workbooks.Open ThisWorkbook.Path & "\..\" & datafile
End If
Else
dataopen = True
End If
On Error GoTo 0
Workbooks(calcfile).Activate
Range("stresslist").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:= _
Range("stressfind"), CopyToRange:=Range("stressout"), Unique:=True
'close data file if not open before
If Not dataopen Then
Workbooks(datafile).Close SaveChanges:=False
End If
End Sub
My first guess is, you need to ensure the Name Range still exists in the workbook or not.
Secondly, as a Best Practice, you should always use the Parent Sheet Name where the Name Range Exists. For example, if my name exists in a sheet called Data, so you should do something like this:
Range("stresslist").AdvancedFilter....
You should use like this:
Dim sht as Worksheet
Dim rng as Range
Set sht = Worksheets("Data")
Set rng = sht.Range("StressList")
rng.AdvanceFilter .....
When you use Global functions like Range, Cells etc, what it tries to do is to try find a range with the name in the active sheet, or the name range stored globally. Avoiding using the hierarchy while making an Object can lead to errors for many reasons which vary from situation to situation. If you would like to know more about your error, please supply with your whole code, and we can then try to find the exact problem.
Thanks,
Vikas B
Found a Method that works for anyone else with the same problem, but takes a little while to run (probably due to the amount of the data) so still looking for a better solution if anybody has one.
datafile = "Datafile.xlsx"
calcfile = ThisWorkbook.Name
dataopen = False
frontend = ActiveSheet.Name
'Copy relevant data
Workbooks(datafile).Activate
stresslist = Sheets("Data").Range("stresslist")
'Create new sheet "Temp" and insert Data
Workbooks(calcfile).Activate
Worksheets.Add.Name = "Temp"
Sheets("Temp").Range("A:C") = stresslist
Worksheets(frontend).Activate
Workbooks(calcfile).Sheets("Temp").Range("A:C").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:= _
Range("stressfind"), CopyToRange:=Range("stressout"), Unique:=True
'Delete Sheet "Temp"
Sheets("Temp").Delete
works by activating the workbook with the data in then copying it into variable, then activating the original workbook and dumping the data into a new "Temp" sheet. Then deleting the "Temp" sheet afterwards.
This works fine but is a lot slower than before, and as the same thing is also being used with more data in another macro that already takes a while to run, I'm still looking for a better way.
Thanks for any better suggestions
Matt
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.