Protecting and hiding sheets in WorkbookOpen disables the screen - vba

I have a routine that is called from the WorkbookOpen event - all it does is hide/unhide the appropriate sheets and protect some of them (I'll put the code below), and it causes an odd problem where there is a picture of the spreadsheet on the screen but anything I do selecting cells, changing values, etc. IS happening to the sheet but is not being shown on the screen - also the sheet tabs are not visible at the bottom.
If I click the close button and then cancel, in the box that asks if I want to save... all my changes are there, the sheet tabs are visible and Excel is working as it should (there is no WorkbookBeforeSave routine, so no code is triggered there)
I'd love to know what's causing this (or even a workaround) as it is driving me nuts.
The code that is called by the Open event is:
Sub ProtectAndHide()
Dim xSheet As Worksheet
Application.ScreenUpdating = False
For Each xSheet In ThisWorkbook.Worksheets
Select Case UCase(xSheet.Codename)
Case "PROPERTIES", "COA", "ASSUMPTIONS", "ENGINE", "EXECSUMM", "NOTES", "DISCLAIMER", "COVER"
xSheet.Visible = xlSheetVisible
xSheet.Protect Password:=HIDDEN.Range("iWord")
Case "COAMAP", "SLDEPN"
xSheet.Visible = xlSheetHidden
xSheet.Protect Password:=HIDDEN.Range("iWord")
Case "HIDDEN", "REPSHEET", "CONTENTSSHEET", "ACTIONS"
xSheet.Visible = xlSheetVeryHidden
End Select
Next xSheet
End Sub

Add Application.ScreenUpdating = True at the end.
Sub ProtectAndHide()
Dim xSheet As Worksheet
Application.ScreenUpdating = False
For Each xSheet In ThisWorkbook.Worksheets
Select Case UCase(xSheet.Codename)
Case "PROPERTIES", "COA", "ASSUMPTIONS", "ENGINE", "EXECSUMM", "NOTES", "DISCLAIMER", "COVER"
xSheet.Visible = xlSheetVisible
xSheet.Protect Password:=HIDDEN.Range("iWord")
Case "COAMAP", "SLDEPN"
xSheet.Visible = xlSheetHidden
xSheet.Protect Password:=HIDDEN.Range("iWord")
Case "HIDDEN", "REPSHEET", "CONTENTSSHEET", "ACTIONS"
xSheet.Visible = xlSheetVeryHidden
End Select
Next xSheet
Application.ScreenUpdating = True
End Sub

Related

changing sheet with macro causes sheet to freeze

My macro for changing sheets doesn't work anymore after I created a few UserForms. Thought the problem was the UserForms were not unloading properly but that doesn't seem to be the case.
When I click the button (which resides in a custom pop up menu) to go to another sheet it works but the sheet acts frozen, I can't scroll or highlight for example.
But if i change sheets by clicking on the tabs then everything is fine. So it would appear that my code to active another sheet is faulty.
My excel workbook has some UserForms, Worksheet_Change and Worksheet_SelectionChange events if that matters.
Is there a better way of doing this. Something that will obviously work and note freeze my sheet after it is activated?
Sheet goto Code:
Sub goto630()
Application.ScreenUpdating = False
Dim sht2 As Worksheet
Set sht2 = ThisWorkbook.Worksheets(2)
Dim sht3 As Worksheet
Set sht3 = ThisWorkbook.Worksheets(3)
sht3.Activate
sht3.Protect _
DrawingObjects:=False, _
Contents:=True, _
Scenarios:=False, _
UserInterFaceOnly:=True, _
AllowFormattingCells:=True
sht2.Visible = True
sht3.Visible = True
On Error GoTo 0
ActiveWindow.Zoom = 90
ActiveWindow.DisplayHeadings = True
ActiveWindow.DisplayHorizontalScrollBar = True
ActiveWindow.DisplayVerticalScrollBar = True
Application.DisplayFormulaBar = True
sht3.DisplayPageBreaks = False
ThisWorkbook.Worksheets(1).Visible = False
ThisWorkbook.Worksheets(4).Visible = False
ThisWorkbook.Worksheets(5).Visible = False
ThisWorkbook.Worksheets(6).Visible = False
ThisWorkbook.Worksheets(7).Visible = False
ThisWorkbook.Worksheets(8).Visible = False
Set sht2 = Nothing
Set sht3 = Nothing
Application.ScreenUpdating = True
End Sub
UserForm Code:
Private Sub UserForm_Click()
Application.OnTime Now + TimeValue("00:00:01"), "Finish"
Unload Me
Call Module2.ScreenRefresh
Exit Sub
End Sub
ScreenRefresh Module is just Application.ScreenUpdating = True read somewhere about this same problem that if the ScreenUpdating is in another module then when called it will fix the freeze issue.
Finish Module is activating the sheet again after the UserForm has been closed (also said to help the freeze issue).
It seems that Excel is waiting for me to click a cell before allowing me to scroll. How can I get around this?
Thanks for any help :)

VBA: Create a filter that hides/shows worksheets

I'm not that "code smart" so I'm terribly sorry for hurting your experienced eyes when gazing upon the mess below :)
The goal: create a simple filter in a master sheet that shows only the sheets that meet a specific value in a cell.
The master sheet is called "MEGAFILTER", the other sheets are called "1", "2", "3", etc. (no quotes)
How I made it work so far (again, sorry!):
Sub MEGAFILTER()
'
' MEGAFILTER Macro
'
'
Sheets("MEGAFILTER").Select
Range("A1").Select
Dim Filter As String
Filter = ActiveCell.Value
'This makes sure all sheets are visible (for subsequent filtering)
For Each ws In ActiveWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next ws
'This is where the real mess kicks in
Sheets("1").Select
If [M2] = Filter Then
Sheets("1").Visible = True
Else
Sheets("1").Visible = False
End If
Sheets("2").Select
If [M2] = Filter Then
Sheets("2").Visible = True
Else
Sheets("2").Visible = False
End If
Sheets("MEGAFILTER").Select
Sheets("3").Select
If [M2] = Filter Then
Sheets("3").Visible = True
Else
Sheets("3").Visible = False
End If
Sheets("MEGAFILTER").Select
'ETC...
End Sub
100 sheets are covered like this. If there are 70 sheets present, it will of course crash when attempting to select 71. The "MEGAFILTER" select makes sure it always lands on the master sheet before it crashes. I realize this is terrible but I didn't succeed to make a proper way :(
Here's how I thought it should be:
Sub MEGAFILTER()
'
' MEGAFILTER Macro
'
'
Sheets("MEGAFILTER").Select
Range("A1").Select
Dim Filter As String
Dim ws As Worksheet
Filter = ActiveCell.Value
For Each ws In ActiveWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next ws
For Each ws In ActiveWorkbook.Worksheets
If ws.Name <> "MEGAFILTER" Then
If [M2] = Filter Then
ws.Visible = True
Else
ws.Visible = False
End If
Next ws
End If
End Sub
But I'm getting a "Next without For" error on that. The intention is that it skips the master sheet (it shouldn't hide that one) and compares the value in cell M2 to the value in cell A1 on the master sheet. If the value is the same, it should show the sheet, if not, it should hide the sheet. Then it should move to the next sheet until all have been checked.
Believe it or not, I spent a few hours with all sorts of combinations on this before I posted this question. I feel like an idiot...
I hope someone can correct my "creativity". Thank you for reading!
Timmy
This should work:
Public Sub MegaFilter()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Mega Filter" Then
ws.Visible = ws.Cells(2, 13) = ThisWorkbook.Worksheets("Mega Filter").Cells(1, 1)
End If
Next ws
End Sub
It checks if cell M2 (Cells(2,13)) on each sheet equals cell A1 on Mega Filter.
In Excel VBA TRUE = -1 and FALSE = 0. The numerical value for xlSheetHidden is 0, xlSheetVisible is -1.
So, if M2=A1 TRUE is returned (-1) and the sheet is made visible, otherwise FALSE is returned (0) and the sheet is hidden.
Sub HideSheet()
Dim sheet As Worksheet
Set sheet = ActiveSheet
' this hides the sheet but users will be able
' to unhide it using the Excel UI
sheet.Visible = xlSheetHidden
' this hides the sheet so that it can only be made visible using VBA
sheet.Visible = xlSheetVeryHidden
End Sub

Excel VBA worksheet event to toggle between hide / unhide

I am working on a project to minimise the number of sheets that are visible in a an excel workbook at any one given time. I am trying to create a parent sheet (which acts as a toggle button) to show/hide child sheets. For example I have a 6 sheets in a workbook: Inputs, Input 1 and Input 2, Outputs, Output 1 & Output 2. Inputs and Outputs will toggle hide and unhide the others worksheets when activated. I have created 2 worksheet level Sub Functions to try and do this. The first one works great, but the other one only works if the first one has been activated and hidden again. Any advice on a better way to do this would be great. I am not sure why excel doesn't have this function already. I tried with arrays, but that doesn't seem to work. I think you need to unhide each tab individually.
'1. Inputs:
Private Sub Worksheet_Activate()
On Error Resume Next
Sheets("Input 1").Visible = True = Not Sheets("Input 1").Visible = True
Sheets("Input 2").Visible = True = Not Sheets("Input 2").Visible = True
Sheets("Input 1").Activate 'needed to deactivate inputs sheet
End Sub
'2. Outputs
Private Sub Worksheet_Activate()
On Error Resume Next
Sheets("Output 1").Visible = True = Not Sheets("Output 1").Visible = True
Sheets("Output 2").Visible = True = Not Sheets("Output 2").Visible = True
Sheets("Output 1").Activate 'needed to deactivate Outputs sheet
End Sub
Here's a link to a file you can download from onedrive:
https://1drv.ms/x/s!Ah_zTnaUo4DzjhWzQ3OTq9tq1APC
Rather than hard-code what should happen when each sheet is selected, I've used a ListObject (i.e. an Excel Table) on a 'Controls' sheet to store the relationships between 'parent' sheets and their various 'children'. The code simply checks this ListObject to see which children belong to which parent, and then takes action accordingly. This has the added bonus of making it very easy for someone who doesn't understand VBA in the slightest to add or amend those Parent/Child sheet relationships in need.
I've also implemented a 'Developer' mode in which the sheet hiding does NOT happen. Nothing more frustrating than trying to do development on an application that treats you like a mere 'user' :-) You can toggle it between 'User' and 'Developer' mode by using the keyboard shortcut Ctrl + Shift + D (D for Developer).
Here's how that looks in the sample file I just put together. I've added the ListObject shown below into a new sheet called 'Controls', and given the ListObject the name of 'VisibleSheets':
I've also added a named range called DeveloperMode, with a value of TRUE:
Here's the code that toggles the application between 'User' mode and 'Developer' mode, that goes in a standard code module:
Public Sub ToggleDeveloperMode()
Dim ws As Worksheet
If ActiveWorkbook.Names("DeveloperMode").Value = "=TRUE" Then
ActiveWorkbook.Names("DeveloperMode").Value = "=FALSE"
Else
ActiveWorkbook.Names("DeveloperMode").Value = "=TRUE"
For Each ws In ActiveWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next ws
End If
End Sub
Here's the code that actually does all the hiding and unhiding, that also goes in a standard code module:
Sub DisplaySheets()
Dim ws As Worksheet
Dim lo As ListObject
Dim lc As ListColumn
Dim vMatch As Variant
Set lo = Range("VisibleSheets").ListObject
If Not [DeveloperMode] Then
For Each lc In lo.ListColumns
If lc.Name = ActiveSheet.Name Then
For Each ws In ActiveWorkbook.Worksheets
Set vMatch = Nothing 'Reset from last pass
vMatch = Application.Match(ws.Name, lo.HeaderRowRange, 0)
If IsError(vMatch) Then 'It's not one of our main sheets
Set vMatch = Nothing 'Reset from last pass
vMatch = Application.Match(ws.Name, lc.Range, 0)
If IsError(vMatch) Then
ws.Visible = xlSheetVeryHidden
Else
ws.Visible = xlSheetVisible
End If
End If
Next ws
End If
Next lc
End If
End Sub
Here's a snippet of code that goes in the ThisWorkbook module that assigns the Keyboard Shortcut of Ctrl + Shift + D to the ToggleDeveloperMode routine so that you can easily toggle between modes. (Don't tell users what this keyboard shortcut is):
Private Sub Workbook_Open()
Application.OnKey "^+D", "ToggleDeveloperMode"
End Sub
And lastly, here's the code triggers the DisplaySheets routine, that also goes in the ThisWorkbook module:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
DisplaySheets
End Sub
It works a treat. Here's what I see when I select each of the 3 Parent sheets in turn:
...and here's what happens when I use the Ctrl + Shift + D shortcut to put the app into 'Developer' mode, ALL sheets are unhidden, including the one with the controls on it.
I'd suggest giving the parent tabs the same color as I have here, so that it's easier for users to understand that they don't change regardless of the other tabs that selectively appear/disappear.
If there's any chance that users (or you) might want to rename the sheets, use codenames instead of sheetnames. Let me know if you're not sure what I'm talking about.
As per user3598756, this question may need some clarification, however it sounds like you trying to emulate behaviour similar to this:
Action Visible Worksheet
------ -----------------
Open Workbook [Input], [Output]
Activate [Input] [Input], [Output], [Input1], [Input2] ' (shows InputX)
Activate [Input1] [Input], [Output], [Input1], [Input2] ' (no change)
Activate [Output] [Input], [Output], [Output1], [Output2] ' (hides InputX, shows OutputX)
This makes [Input] and [Output] your only gateway worksheets, so the following on [Input] (and the converse for [Output]) would achieve this.
Private Sub Worksheet_Activate()
Sheets("Input 1").Visible = True
Sheets("Input 2").Visible = True
Sheets("Output 1").Visible = False
Sheets("Output 2").Visible = False
End Sub
Notes
Avoid using On Error Resume Next unless you have a specific reason to. It's usually a good thing that your code grinds to a halt if there is something wrong, as opposed to keeping its little secrets to itself and leaving you none the wiser.
The .Visible property is itself a Boolean, so the conditional .Visible = True is equivalent to using just .Visible by itself.
Your .Visible statements are probably not resolving how you intended them to. Only one of your = on each line will be an assignment operator, the others will be equality checks. In the absence of brackets, it will be your first =, and the other = will be step-by-step equality checks working from the right to the left. This is operator precedence at work.
Regarding the last point, say sheet Input 1 is visible, your first line will resolve as:
Sheets("Input 1").Visible = True = Not Sheets("Input 1").Visible = True
Sheets("Input 1").Visible = True = Not <True> = True
Sheets("Input 1").Visible = True = Not <True>
Sheets("Input 1").Visible = True = <False>
Sheets("Input 1").Visible = <False>
Where what I believe was intended is:
Sheets("Input 1").Visible = Not Sheets("Input 1").Visible ' i.e. toggle my visibility
These things can be hard to pick up with booleans, because even if your logic is wrong, the result can be right 'half' of the time.
I have managed to make this work. The issue was had something to do with trying to use the "Outputs" Private Sub Worksheet_Activate() function when the "Input 1" sheet was activated and hidden. I have added another tab called "Main" to replace this, so "Main" will always be the active tab after the function has been activated. This resolves the issue although it would be better if the focus didn't jump around the workbook while navigating what in each "folder". Here is the updated code...
'Inputs "Parent folder" sheet
Private Sub Worksheet_Activate()
On Error Resume Next
Sheets("Input 1").Visible = True = Not Sheets("Input 1").Visible = True
Sheets("Input 2").Visible = True = Not Sheets("Input 2").Visible = True
**Sheets("Main").Activate** 'needed to deactivate Inputs sheet
End Sub
'Outputs "Parent folder" sheet
Private Sub Worksheet_Activate()
On Error Resume Next
Sheets("Output 1").Visible = True = Not Sheets("Output 1").Visible = True
Sheets("Output 2").Visible = True = Not Sheets("Output 2").Visible = True
**Sheets("Main").Activate** 'needed to deactivate Outputs sheet
End Sub
I think this is a great way to simplify workbooks with may tabs. It could defiantly be improved so look forward to hearing any suggestions.
Here is a link to my working file
https://1drv.ms/x/s!AvtNNMCst1bIgxjCBCemZlCerHMo

hiding selected worksheets without for loop

I would like to hide some worksheets, all at once, without using for loop. The reason for this is a big number of worksheets, so my macro works a while.
Do you have any ideas how can I improve the running time of this macro?
You can just record a macro of selecting the first sheet, and then select the last sheet with Shift. Then you right-click and Hide.
Sheets(Array("Sheet2", "Sheet3", "Sheet4")).Visible = False
Or by index
Sheets([{2, 3, 4}]).Visible = False
Note that you can not unhide more than one sheet at a time.
To add a custom view with all sheets visible:
For Each ws In Sheets
ws.Visible = True
Next
ActiveWorkbook.CustomViews.Add "All" ' you can change the name
Then, to un-hide all sheets:
ActiveWorkbook.CustomViews("All").Show
To un-hide the sheets faster, you can try disabling some of the events and calculation:
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
For Each ws In Sheets: ws.Visible = True: Next
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Sub HideSheets()
Dim sSheets() As String
sSheets = Split("Sheet1,Sheet2,Sheet3", ",")
Worksheets(sSheets).Visible = xlHidden
End Sub

Reorder hidden tabs in excel

At work, we've developed a tool using Excel and VBA. This tool has hidden sheets that will only be opened once the previous step is complete. One of the issues I'm running into from the previous coder is that the very last step, there is an extra button, let's call it A, that can be clicked. Based on the order of sheets the previous coder created, this sheet was second out of 10, and when A is clicked, its automatically goes to the second position.
Is there any way I can modify it to the the right most tab?
The problem I run into is when I get to the final step, I can manually move the tab to the right hand side, but that is only after I have finished my analysis, and can not go to the beginning, so it does not allow me to save.
This will move your hidden sheet to end of all visible sheets:
Sub test()
With Sheets("Sheet1")
.Visible = True
Sheets("Sheet1").Move After:=Sheets(Sheets.Count)
.Visible = False
End With
End Sub
And this will move your hidden sheet to the end of all hidden and visible sheets:
Sub moveHiddenSheet()
Dim ws, x, lastSheet
x = 0
For ws = Worksheets.Count To 0 Step -1
x = x + 1
If Sheets(Worksheets.Count - x).Visible = False Then
Sheets(ws).Visible = xlSheetVisible
lastSheet = Sheets(ws).Name
Exit For
End If
Next ws
With Sheets("Sheet1")
.Visible = True
Sheets("Sheet1").Move After:=Sheets(Worksheets.Count)
.Visible = False
End With
Sheets(lastSheet).Visible = False
End Sub