Stop Excel from changing active sheet on Sheets.Visible = True command - vba

I have a large workbook with many sheets used for background calculation that I hide when they are not in use. The workbook is locked down (no ribbon, sheet tabs, formula bar, etc) so it cannot be tampered with when it is in use.
In Excel 2010, everything went smoothly and the active sheet was not changed, but now in Excel 2016 the following Sub changes the active sheet to the "CompCalc" sheet which leaves the user with no way to return to the sheet they need to be on to use the workbook.
Sub MakeSheetsVisible(Status As Boolean)
Dim VarSubName As String
VarSubName = "MakeSheetsVisible"
'***********************************************************
ProtectSheets (False)
Sheets("DATA_INPUT").Visible = Status
Sheets("RAW_DATA").Visible = Status
Sheets("MASTERHISTORY").Visible = Status
Sheets("CompCalc").Visible = Status
'Sheets("Event_Enter").Visible = Status
Sheets("Raw_Chart_Data").Visible = Status
End Sub
This Sub is called at the end of a Sub that is called from another Sub which can be triggered 1 of 2 ways, on a button press or ListView double click. The active sheet is only changed in the above routine when the button is used to call the initial Sub and when the routine is ran continuously (not stepped through with F8).
I can work around this issue by checking the original active sheet at the beginning of the routine and setting it back to the original at the end, but I would like to know why this is happening and if there is a way to stop it without a workaround. Any help is appreciated

It's an annoying bug in Excel 2013/2016 and as far as I know, there is no fix. A workaround I use is:
Set CurrentSheet = ActiveSheet
'Instructions here
CurrentSheet.Activate

I only ever use active sheet if it's needed for something specific. (as per MatthewD)
But surely when you've set all your sheets to visible, you can add another line to make the sheet you want to be active?
Sheets("The one you want").Activate
would do the job? (or maybe .select?)

Related

VBA VeryHidden multiple tabs

I have done research and for whatever reason I cannot get this simple code to work correctly. Simply put, I am trying to xlveryhidden 5 tabs, but I receive run-time error 1004. If anything, it would be nice to change from the Sheet names to code names in case I change the tab names:
Sheet1 - Calculations
Sheet2 - LY Rates
Sheet3 - TY Rates
Sheet4 - Client Details
Sheet5 - Census
Sub VeryHiddenTabs()
Sheets(Array("Calculations", "LY Rates", "TY Rates", "Client Details", "Census")).Visible = xlVeryHidden
End Sub
I was able to use this to set my sheets to .Visible = False.
Sub HideMySheets()
Sheets(Array(Sheet1.Name, Sheet2.Name, Sheet3.Name, Sheet4.Name, Sheet5.Name)).Visible = False
End Sub
Unfortunately, it turns out you are not allowed to use this method to set them to .Visible = xlVeryHidden. Instead you have to do it on a per-sheet basis, using #Ibo's method.
Based on what you have provided it seems you are trying to make all of the sheets very hidden, you cannot do this. You MUST have at least one VISIBLE sheet in the workbook.
Additionally, to use VBA to make sheets very hidden not using the sheet names, you should then use the sheet indexes or sheets' code name. Sheets code name cannot be change using the interface so the code would work with whatever the sheet name is. To change the sheets' code name, go to VBE (ALT + F11), double click on the sheet you want and change the name, which is the first item in the properties window, if you don't see the properties window click F4. Let's say you change the code name of the sheet to mySht1 then you can do:
mySht1.Visible = xlVeryHidden
if you use the index of the sheets to change the visibility you can do this:
ThisWorkbook.Sheets(1).visible=xlVeryHidden
if you want to use this method, you need to always have one visible sheet so you have to create a sheet and then run this code:
Sub VeryHiddenTabs()
For i = 1 To ThisWorkbook.Worksheets.Count - 1
ThisWorkbook.Worksheets(i).Visible = xlVeryHidden
Next
End Sub
since you have already had the sheet you have mentioned, then Excel will make all of the very hidden. The above routine will keep the last created sheet visible and the rest very hidden.

Excel slowed down after using 'on active cell change' macro

I recently experimented with a macro that runs every time the active cell column changes:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cell As Integer
cell = ActiveCell.Column
Select Case cell
'code
End Select
End Sub
I quickly realized that this slows down Excel by a lot, so I turned the macro off. The problem is that it must have turned something on, because now every time I change the active cell in any Excel file on my computer, it loads a little bit, like if that macro was still running.
I deleted the macro, restarted the computer, but nothing.
If I manually turn off events (Application.EnableEvents = False), this problem goes away, but as soon as I open another Excel file (any file, not just the one I wrote the macro in), it turns back on.
What have I done and how do I turn it off?
The way you describe it, it seems that you have Saved the Worksheet_SelectionChange event to a personal.xlsb file.
Find it, delete the code and enjoy your Friday!
https://support.office.com/en-us/article/Copy-your-macros-to-a-Personal-Macro-Workbook-aa439b90-f836-4381-97f0-6e4c3f5ee566

Call Sub only if a USER changes the worksheet, not VBA code

I have a Worksheet_Change event where if a cell in column F changes, a message pops up asking if the user wants to change the cell text.
Now, I have VBA code that inserts new rows and, therefore, makes changes in column F, but I don't want the message to pop up or this code to be called at all.
Is there a way to distinguish between a user and Excel itself (VBA) making a change on the worksheet?
Just insert the line
Application.EnableEvents = False
before executing your code and then (at the end) set
Application.EnableEvents = True
again to make sure that Excel reacts to Events on the worksheet again.
For more information read this: https://msdn.microsoft.com/en-us/library/office/ff821508.aspx

VBA code to go to previous page

I want to write a VBA code to go to previous sheet. A code with I will be able to add a button to every sheet and by pushing it I will go back to the last (previous) sheet from which I got to the present sheet.
Example: I go to sheet1 from sheet7. Now in sheet1 there is back button through which i can go back to sheet 7. Something "similar" to the "BACK" button in Internet Explorer.
Can anyone help me with this
Put this in a regulare code module (Module1 in my case):
Public PreviousSheetNum As Integer
Sub GoBack()
Worksheets(PreviousSheetNum).Activate
End Sub
And in the ThisWorkbook module, put this code:
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
Module1.PreviousSheetNum = Sh.Index
End Sub
So basically whenever the user changes sheet, the index of the previously selected sheet is remebered, and you can go back to that sheet any time you wish.
Be warned though that changing sheet order or deleting sheets might produce unexpected behaviour. You can change from remembering the sheet index to remembering it's name, but it has some possible issues too.
Hope this helps.

How to capture worksheet being added through Copy/Paste in Excel VBA

I am trying to capture worksheets being copied in to a workbook from another workbook.
Workbook_NewSheet event does not trigger when the sheets are copied from another workbook.
It is triggered only if the user manually inserts them through (Insert->Worksheet menu option), or when you add a new sheet through VBA as ThisWorkbook.Worksheets.Add.
What I am trying to capture is basically a Paste operation which is resulting in a new sheet.
This might be from any of the below user actions:
User copies an existing sheet by dragging it holding Control Key (which adds a new sheet)
User copies sheet/s from another workbook
user moved sheets from another workbook
or any of the below VBA code:
SourceWorkbook.Sheets(“SourceSheet”).Copy Before:=TargetWorkbook.worksheets(“SheetNameIn Target”) 'copy across workbook'
SourceWorkbook.Sheets(“SourceSheet”).Move Before:=TargetWorkbook.worksheets(“SheetNameIn Target”) 'move across workbook'
ThisWorkbook. Sheets(“SheetName”).Copy 'copy within workbook'
If you know any way of capturing this action/macro results within VBA that would be greatly helpful.
Please note that I do not want to avoid such an user action (so i do not want to secure the workbook) but I want to handle the pasted sheet programatically to verify the data, and if the similar sheet already exists then update the existing sheet rather than having same data in two sheets.
When a sheet is copied, its name will always end with "(2)", or at least ")". You could check on that like this
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name Like "*(2)" Then
Application.DisplayAlerts = False
Sh.Delete
Application.DisplayAlerts = True
End If
End Sub
The SheetActivate event will fire under all of those circumstances. Obviously it will fire under a lot of other circumstances too. This sounds like a royal pain, but you could maintain your own collection of worksheets and compare your collection to the ThisWorkbook.Sheets collection to see if something was added/deleted.
If you're trying to prevent it, you might consider protecting the workbook structure instead of doing it in code.
The way I have it implimented is
Private Sub Workbook_WindowActivate(ByVal Wn As Window)
ToggleMenuOptions False, 848, 889
End Sub
Private Sub Workbook_WindowDeactivate(ByVal Wn As Window)
ToggleMenuOptions True, 847, 848, 889
End Sub
Public Function ToggleMenuOptions(bToggle As Boolean, ParamArray ControlID() As Variant) As Boolean
'848 Move or Copy Sheet...
'889 Rename Sheet
'847 Delete Sheet
On Error GoTo lblError
Dim oControl As CommandBarControl, oControls As CommandBarControls, iControl As Integer
If IsMissing(ControlID) Then
ToggleMenuOptions = False
Exit Function
End If
For iControl = LBound(ControlID) To UBound(ControlID)
For Each oControl In Application.CommandBars.FindControls(ID:=ControlID(iControl))
oControl.Enabled = bToggle
Next
Next
ToggleMenuOptions = True
Exit Function
lblError:
If Err.Number Then
ToggleMenuOptions = False
Exit Function
End If
End Function
Private Sub Workbook_NewSheet(ByVal Sh As Object)
MsgBox "Please use Add New Project option in custom Toolbar to add new sheets!!", vbExclamation, "Not Supported"
Application.DisplayAlerts = False
Sh.Delete
Application.DisplayAlerts = True
End Sub
So my users wont be able to rename, add or delete sheets. This is working pretty well for now.
The only way I can think of doing this without maintaining a separate sheets collection is to maintain a static array of sheet names (or sheet codenames) and compare this to the actual sheets in the workbook each time the SheetActivate event fires to detect any additions. If you don't want to/can't keep the list in an array you could always use a hidden sheet to store the list. Whether this is any more or less of a pain than maintaining a separate collection is debatable :)
I am working on something similar but cannot block any of the user menu actions. I have sheets whose type are important - each sheet is either a Master or Slave - each Master sheet sums over the Slave sheets beneath it and I need to keep these formula clean.
Rather than maintain a list of sheets in an extra hidden sheet, I am defining 2 hidden names on each sheet recording the offset of the index of the Sheet to its linked Master sheet, and a reference to the linked Master sheet. So if my sheet is (say) +2 tabs from its Master sheet, then on Sheet activate/deactivate (not sure which of these is better to track at this stage) this offset will have changed if anything gets inserted, deleted or moved. This covers most or all of the events that would arise from moving or copying sheets.
If the sheet has been moved, I cycle through the workbook and calculate new Master/Slave index references for every sheet.
Will post code when I get this reasonably stable but it seems like a scheme that would work in a wide variety of circumstances.