I am setting the Locked property of a small range, but the code fails with the familiar 1004 cannot set the Locked property of the Range class, similar to this problem.
The range in question does not contain any merged cells
My sheet is locked with UserInterFaceOnly=True
I am out of ideas - how can I find out what is causing this to fail?
EDIT: I failed to mention that I am locking the sheet, saving it, closing and re-opening - and the code for setting the Locked-property is triggered in Workbook_Open.
This leads to a design issue caused by the fact that re-opening the workbook removes the interface-only protection, leaving the entire sheet protected. Thanks to #CLR for putting me on that path, and credit goes to him if he decides to submit it as an answer.
Lock code:
Sub LockSheet()
If ws1.ProtectContents = False Then ws1.Protect Password:="1", UserInterFaceOnly:=True
End Sub
Code snippet that fails when the sheet is protected (but works if I unprotect the sheet):
With summaryRange
.Locked = Not (someBoolVar) ' <-- 1004 Cannot set Locked etc.
.FormulaHidden = Not (someBoolVar)
End With
where summaryRange is qualified and working in other parts of the code:
Set summaryRange = ws1.Range(firstSummaryColumn & "4:" & lastSummaryColumn & lastRow)
& also verified working by the compiler:
? Module1.summaryRange.Address
$J$4:$M$50
I have tried to reproduce your problem and can't, using the below subs to mimic your code.
Sheet protection:
Sub LockSheet()
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
If ws1.ProtectContents = False Then
ws1.Protect Password:="1", UserInterFaceOnly:=True
Else
ws1.Unprotect Password:="1"
End If
End Sub
Range locking:
Sub lockit()
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Dim someBoolVar As Boolean
someBoolVar = True
Dim summaryRange As Range
Set summaryRange = ws1.Range("$J$4:$M$50")
With summaryRange
.Locked = Not someBoolVar ' <-- No error triggered here
.FormulaHidden = Not someBoolVar
End With
End Sub
Possible causes:
Your summaryRange is not properly defined: you have debunked this in your Q.
Something fishy is happening with the sheet locking: I have debunked this above.
Your someBoolVar is not properly defined. Note in my above code, I have defined someBoolVar as True, and the code works. Try debugging ?someBoolVar in the immediate window to see what it is before it is used. Edit: you have debunked this too.
Edit:
As suggested in the comments, your issue is probably that the UserInterfaceOnly flag gets reset to False when the workbook is closed. To sidestep this, you will have to re-apply the protection when the workbook opens. This sub will achieve that:
Sub reprotect()
' Called from the Workbook_Open event
' Cycle through sheets
Dim sh As Worksheet
For Each sh In ThisWorkbook.Sheets
' If protected, reprotect to reset UserInterfaceOnly flag
If sh.ProtectContents = True Then
sh.Unprotect Password:="1"
sh.Protect Password:="1", UserInterfaceOnly:=True
End If
Next sh
End Sub
Fortunately, the Locked property of ranges is not affected by the workbook being closed, so you will not have to re-apply that condition again!
The Office VBA documentation doesn't address this problem, but the VB documentation (often comparable) in fact does:
If you apply this method with the UserInterfaceOnly argument set to true and then save the workbook, the entire worksheet (not just the interface) will be fully protected when you reopen the workbook. To re-enable the user interface protection after the workbook is opened, you must again apply this method with UserInterfaceOnly set to true.
Related
I have many sheets in a workbook. I have a main sheet/"form" called "JE" and on that sheet there are buttons and macros that lead to other sheets in the workbook. But, the intention is for other users, not myself, to use the workbook. So, I would only like the sheet that is being used to be visible at any given time. At no time do I want more than 1 sheet to be visible by the user. The user can navigate the workbook mainly thru clicking buttons and certain cells in select sheets that will allow them to navigate throughout the entire workbook. I have tried this by adding code into 'ThisWorkbook' module but it doesn't seem to working as I'd like. When I navigate to one sheet and back to another, some sheets remain visible when I'd like them to be hidden so I'm unsure of what other modifications I can make to code below to get my desired result. If anyone can offer up any modifications or changes I can make to accomplish this, I'd really appreciate it.
UPDATE:
I have added this code to my 'ThisWorkbook' Object:
Option Explicit
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim MySh As Worksheet
For Each MySh In ThisWorkbook.Worksheets
If MySh.Name <> Sh.Name Then MySh.Visible = 0
Next MySh
End Sub
but, when I go to double-click values that usually populate cells in my main sheet ("JE") I get a run-time 1004 error. The values still populate the main sheet but it no longer navigates back to the main sheet as I'd like.
If anyone knows of a solution or a mod I can make, I'd really appreciate it.
The code is nice. Simply put it in the Workbook part of the VBA project:
Option Explicit
Private Sub Workbook_Open()
Dim MySh As Worksheet
For Each MySh In ThisWorkbook.Worksheets
If MySh.Name = ActiveSheet.Name Then MySh.Visible = xlSheetHidden
Next MySh
End Sub
The ThisWorkbook part is here:
In general, I use always something similar, when I am starting an Excel application. I define two Arrays with Visible and Invisible Worksheets and I iterate over them, making them either visible or not visible. Like this:
Option Explicit
Public Sub HideNeeded()
Dim varSheet As Variant
Dim arrVisibleSheets As Variant
Dim arrHiddenSheets As Variant
arrVisibleSheets = Array(Sheet1)
arrHiddenSheets = Array(Sheet2, Sheet3)
For Each varSheet In arrVisibleSheets
varSheet.Visible = xlSheetVisible
Next varSheet
For Each varSheet In arrHiddenSheets
varSheet.Visible = xlSheetVeryHidden
Next varSheet
End Sub
xlSheetVeryHidden makes it possible to unhide it only from the VB Editor. Otherwise you need xlSheetHidden.
It should be Workbook_SheetActivate:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim MySh As Worksheet
For Each MySh In ThisWorkbook.Worksheets
If MySh.Name <> Sh.Name Then MySh.Visible = 0 'zero - false, 1 - true, 2 - very hidden
Next MySh
End Sub
Sub HideInactive()
Set theActiveSheet = ActiveSheet
For Each Sheet In ThisWorkbook.Worksheets
If Sheet.Index <> theActiveSheet.Index Then Sheet.Visible = False
Next
End Sub
I 've test the code. Thank you for reading.
TL;DR
making worksheet visible produces error due to worksheet protection, even though worksheet is NOT protected!
The problem in prose:
I've created a an application in excel that uses individual worksheets as user interfaces. At the top, I have a list of objects that serve as buttons to navigate the application. This works as expected most of the, but on occasion produces an error due to worksheet protection, this despite the worksheet not being protected.
The code that is called by the buttons:
Public Sub HideAllOtherSheets(targetSheet As Worksheet)
Dim Wkb As Workbook
Dim wks As Worksheet
Set Wkb = ThisWorkbook
'Ensure target sheet is visible
For Each wks In Wkb.Worksheets
If wks.Name = targetSheet.Name Then
wks.Visible = xlSheetVisible
End If
Next wks
'Now make all others invisible
For Each wks In Wkb.Worksheets
If wks.Name <> targetSheet.Name Then
wks.Visible = xlSheetVeryHidden
End If
Next wks
Set Wkb = Nothing
End Sub
The error:
The runtime error 1004 occurs on the line wks.Visible = xlSheetVisible in the first For ... Each, but it does not occur consistently.
Strangest of all... if I then go to debug and simply press F5, it continues running without repeating the error message!
I was experimenting with using .Protect UserInterfaceOnly:=True but have taken that code out again. Since experimenting with that I have had this problem.
What I have tried:
I inserted a direct .Unprotect statement in the line prior to the one making the worksheet visible, but the error still occurs. To the best of my knowledge it shouldn't even matter that the worksheet is locked.
Inserted code that unlocks all worksheets when the workbook is opened. Error still occurs.
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 have a work book with several worksheets that I would like to protect. I am not using a password on the protection. I have some visual basic code associated with this sheet to expand the row width on merged cells. The code will not work when the sheets are protected.
I did find some guidance on adding unprotect code to my code, but can't figure out where to put it and how to address the fact that there is no passord. Further guidance woudl be greatly appreciated!
Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim NewRwHt As Single
Dim cWdth As Single, MrgeWdth As Single
Dim c As Range, cc As Range
Dim ma As Range
With Target
If .MergeCells And .WrapText Then
Set c = Target.Cells(1, 1)
cWdth = c.ColumnWidth
Set ma = c.MergeArea
For Each cc In ma.Cells
MrgeWdth = MrgeWdth + cc.ColumnWidth
Next
Application.ScreenUpdating = False
ma.MergeCells = False
c.ColumnWidth = MrgeWdth
c.EntireRow.AutoFit
NewRwHt = c.RowHeight
c.ColumnWidth = cWdth
ma.MergeCells = True
ma.RowHeight = NewRwHt
cWdth = 0: MrgeWdth = 0
Application.ScreenUpdating = True
End If
End With
End Sub
You could probably do something like this:
Surround your code with .Unprotect and .Protect
Sub protectSheet()
Dim ws As Worksheet
Set ws = Sheets(1)
With ws
.Unprotect "password"
'Insert Code Here
.Protect "password"
End With
End Sub
try this:
Private Sub Workbook_Open()
Dim wSheet As Worksheet
For Each wSheet In Worksheets
wSheet.Protect Password:="Password_here", _
UserInterFaceOnly:=True
Next wSheet
End Sub
Put this code in 'ThisWorkbook' then use the Workbook_Open Event.
This code protects all the WS everytime you open the WB
but allows macro to run due to UserInterfaceOnly set to true
You need to protect the sheet with password.
If you want a user to edit some cells even if the worksheet is protected then set the locked property of those cells to false before protecting the sheet.
Now when Worksheet_Change is triggered or any procedure is called which is trying to make some changes to excel range (locked cells = true) then you need to Unprotect the Sheet at beginning of the code and protect it at the end again. You may refer #sobin answer for syntax.
Also you may use error handlers and explicitly protect the sheet. This is done to avoid situation wherein the sheet is unprotected and then there is error which comes up for any reason then that would leave the sheets unprotected.
With the help of Excel forum, I have created a user login form where I have 5 users. Each user can have access to the sheets assigned to him/her only. This is working fine. But now I have protected the "workbook structure" so as to avoid users' adding/deleting sheets. Then I login again, and instead of displaying the login form, the error message pops up in Excel VBA:
Error-1004 Unable to set the visible property of the worksheet class
When I debug the error is highlighted in the following codes where the visible property of the worksheet is set as "True", "False" or "xlSheetVeryHidden".
Private Sub Workbook_Open()
Dim wsSht As Worksheet
Worksheets("Splash").Visible = True
Worksheets("Users").Visible = False
For Each wsSht In Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
With Worksheets("Splash")
.Visible = True
.Activate
End With
frmLogin.Show
bBkIsClose = False
End Sub
Is there a way to correct this so as I can access the login form as I did prior to password protecting the "workbook structure"?
Here is another concern about this.
You can NOT hide ALL of the worksheets in a workbook. As such if you know you are going to have at least 1 sheet that will ALWAYS be visible, exclude it from the hiding process.
Did you have another Excel Workbook opened at the same time when testing it? There's no explicit reference to the book you're looking for, so in case you run this code having a workbook where the "Splash" sheet is not available, the macro will try to set all sheets to hidden, which may raise this error.
To simulate it, open a new Excel session and run this macro:
Sub test()
Dim oSheet As Excel.Worksheet
For Each oSheet In Worksheets
oSheet.Visible = xlSheetVeryHidden
Next oSheet
End Sub
If I'm not barking to the wrong tree, you'll get the same error.
To solve it, simply add the workbook name into your loop, and it would be like this (obviously, you must ensure that there's a "Splash" sheet, or the error will arise):
For Each wsSht In Workbooks("Mybook.xlsm").Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
Rgds
You'll have to unprotect and reprotect in code. The downside is that your password will be in the code.
Private Sub Workbook_Open()
Dim wsSht As Worksheet
Me.Unprotect "password"
Me.Worksheets("Splash").Visible = True
Me.Worksheets("Users").Visible = False
For Each wsSht In Me.Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
With Me.Worksheets("Splash")
.Visible = True
.Activate
End With
frmLogin.Show
bBkIsClose = False
Me.Protect "password", True, False
End Sub
I'm not sure if this is relevant, but I found this question when I was searching for how to hide the last (and only) worksheet. The reason for wanting to do this is because the file is a startup file that contains company-wide macros that should not be edited by the user. I discovered that while the Worksheet needs to be kept open, the Window displaying it does not.
Here's an example:
Sub spork()
Dim x As Workbook
x.Windows.Item(1).Visible = False
End Sub
Now, Excel opens the file with no worksheet visible.
Sometimes there is a "glitch" (a.k.a. "feature" or "bug"), simply returning this error due to no visible reason. Not the worksheet protection, neither the fact that this is the last worksheet visible. To fix the "feature" this worked for me:
Public Sub UnhideAll()
Dim wks As Worksheet
For Each wks In ThisWorkbook.Worksheets
wks.Visible = xlSheetVisible
Next
End Sub