Excel VBA: How To Disable Protected Sheet Dialog On Keydown - vba

After doing a File > Protect Workbook > Protect Current Sheet > Unselect All > Okay
Anytime I press a keydown while viewing the sheet I get a
"The cell or chart you're trying to change is on a protected sheet." dialog.
I'd like to disable this.
I currently have a Auto_Open macro which does a Application.DisplayAlerts = False
This does not seem to help, even though I'm sure the macro is running on startup.
Any ideas?

So here is a workaround by kskinne:
1) Make sure all cells you don't want changed are locked Format Cells > Locked
2) Then instead of protecting worksheet use the following code in the code pane for the sheet of interest.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Locked = True Then Application.Undo
Application.EnableEvents = True
End Sub
I like this solution. I don't think switching-off DisplayAlerts will work. I put
Application.DisplayAlerts = False into Worksheet_Activate event and the message still fired.

Related

Excel only when VBA is enabled it should be possible to save the file, possible?

I have a file that I made with three levels of permissions.
You get prompted to input a password on a userform and you get either admin rights, read/write or only read permissions.
That works fine, unless you don't enable macros.
If you don't enable the macro prompting the userform is not shown and the rights are not set thus you have full access.
I have seen you can use a splash screen but for that to work you need to save the workbook as far as I understand?
The basic concept of them is to beforeclose hide sheets and unhide splash screen, then save the workbook.
But what if the user made a mistake and what to close without save and reopen later? The file gets closed with all sheets visible?
So I thought maybe I can use the "explorer -> right click -> properties -> Read-only" attribute as an extra layer of protection?
I found these functions.
ActiveWorkbook.ChangeFileAccess Mode:=xlreadonly
ActiveWorkbook.ChangeFileAccess Mode:=xlreadwrite
But I tried the readonly line and it did set read only, file could not be saved.
Then I closed the workbook without saving and opened again. But it seems the attribute was not set in the properties of the file since it was not tickmarked and when I opened the file I could save it.
Is there any other way to solve this?
I want to either "force" VBA on the user or make sure he/she can't save the file if it's opened without VBA.
I found a solution that seems to work.
You can in Workbook_BeforeClose use this line to make the file read-only in file properties.
SetAttr Application.ActiveWorkbook.FullName, vbReadonly
This will set the tickmark in the properties and Excel will notice the file is writeprotected.
Then in Workbook_Open() (or as in my case when rights has been established)
SetAttr Application.ActiveWorkbook.FullName, vbReadwrite
ActiveWorkbook.ChangeFileAccess Mode:=xlReadWrite
The first line removes the tickmark in file properties, but Excel still "remembers" the file as read-only.
The second line will tell Excel to make it ReadWrite and the file works as normal again.
This is a far more complicated method than Adreas', but doesn't feature the same risk of mildy tech-savvy users just right-clicking the file and popping into the "Properties" panel.
Create 2 new worksheets. One of them is set to xlVeryHidden - for the examples below, I have called it hsSheetStatus. The other, with a nice large notice telling your hapless minion colleague to enable Macros, will be changing visibility. I have called this hsEnableNotice.
Then I have a Macro to show hsEnableNotice hide all of the other sheets (storing their visibility and the ActiveSheet on hsSheetStatus), and a second Macro to do the reverse (restore visibility/ActiveSheet from hsSheetStatus) and set these to run on Workbook_BeforeSave, Workbook_AfterSave and Workbook_Open:
Option Explicit
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
UnlockAndShow
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
LockAndHide
End Sub
Private Sub Workbook_Open()
UnlockAndShow
End Sub
Private Sub LockAndHide()
Dim lSheet As Long, ActiveName As String
Application.ScreenUpdating = False
Application.EnableEvents = False
ActiveName = ThisWorkbook.ActiveSheet.Name
hsEnableNotice.Visible = xlSheetVisible
hsEnableNotice.Activate
hsSheetStatus.Range(hsSheetStatus.Cells(1, 1), hsSheetStatus.Cells(hsSheetStatus.Rows.Count, 1)).EntireRow.Delete
For lSheet = 1 To ThisWorkbook.Sheets.Count 'By using Sheets instead of Worksheets, we include Charts etc
hsSheetStatus.Cells(lSheet, 1).Value = ThisWorkbook.Sheets(lSheet).Name
hsSheetStatus.Cells(lSheet, 2).Value = ThisWorkbook.Sheets(lSheet).Visible
If ThisWorkbook.Sheets(lSheet).Name = ActiveName Then hsSheetStatus.Cells(lSheet, 3).Value = 1
If ThisWorkbook.Sheets(lSheet).Name <> hsEnableNotice.Name Then ThisWorkbook.Sheets(lSheet).Visible = xlSheetVeryHidden
Next lSheet
ThisWorkbook.Protect Password:="ThisIsMyPassword.ThereAreManyLikeIt,ButThisOneIsMine.", Structure:=True, Windows:=False
Application.EnableEvents = True
End Sub
Private Sub UnlockAndShow()
Dim WasSaved As Boolean, lSheet As Long, lMax As Long
WasSaved = ThisWorkbook.Saved
Application.ScreenUpdating = False
Application.EnableEvents = False
lMax = hsSheetStatus.Cells(hsSheetStatus.Rows.Count, 1).End(xlUp).Row
ThisWorkbook.Unprotect Password:="ThisIsMyPassword.ThereAreManyLikeIt,ButThisOneIsMine."
For lSheet = 1 To lMax
ThisWorkbook.Sheets(hsSheetStatus.Cells(lSheet, 1).Value).Visible = hsSheetStatus.Cells(lSheet, 2).Value
If hsSheetStatus.Cells(lSheet, 3).Value = 1 Then ThisWorkbook.Sheets(hsSheetStatus.Cells(lSheet, 1).Value).Activate
Next lSheet
hsSheetStatus.Visible = xlSheetVeryHidden
hsEnableNotice.Visible = xlSheetVeryHidden
Application.EnableEvents = True
Application.ScreenUpdating = True
ThisWorkbook.Saved = WasSaved
End Sub

Disable alert when manually deleting a sheet

Is there a way in VBA to disable the alert that pops up when MANUALLY deleting a sheet (right click sheet and delete)? I have seen Application.DisplayAlerts = False, however this seems to only work for me when deleting a sheet using VBA (Sheets("Sheet1").delete). I am trying to disable the alert for the whole workbook when you manually right click on a sheet and click delete. Thanks.
In case anyone else is looking for the same scenario:
...eliminate the need to confirm deleting a sheet when presenting the
workbook in meetings. While going through the sheets I often double
click on pivot tables to view detail, and I would like to eliminate
the pop-up alert when I delete the generated sheet...
If new sheets are generated only when double-clicking a pivot table, this might be a suitable solution
Placed in ThisWorkbook, the code bellow will delete any new sheets, when selecting a different sheet
Option Explicit
'Place this code in ThisWorkbook module
'Expects that all new sheets are generated by double-clicking a pivot table
Private pivotWs As Worksheet
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Set pivotWs = Sh
End Sub
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
If Not pivotWs Is Nothing Then
If Sh.Name = pivotWs.Name Then
Application.DisplayAlerts = False
pivotWs.Delete
Set pivotWs = Nothing
Application.DisplayAlerts = True
End If
End If
End Sub

VBA code conflict

I know, I am asking an unusual question. But, please do help me.
I have a below code on Workbook that will take care of copy/paste data on sheets. It would allow me to paste data into the cells without changing format(past only values).
Basically, the code will use destination formatting. similar to "paste values". It would allow the user to paste data from any other format. So that format is consistent across sheets.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim vNewValues as Variant
NewValues = Target
Application.EnableEvents = False
Application.Undo
Target = NewValues
Application.EnableEvents = True
End Sub
Along with above code, I also have another code on the sheet that will help me to clear the contents and code is linked to a button. So, when the button is pressed it will clear the contents of the sheet.
Private Sub ResetKey_Click()
If MsgBox("Content of the sheet will be deleted and cannot be restored", vbOKCancel + vbInformation) = vbOK Then
Worksheets("User").Range("E19:I3018").ClearContents
Else
Exit Sub
End If
End Sub
Concern: I see a conflict between these codes. Because, when I click on the button I get the error that will point me to Application.Undo in the first code. I tried debugging the code but I was not able to get both to work. Please Suggest.
This will work:
Private Sub ResetKey_Click()
If MsgBox("Content of the sheet will be deleted and cannot be restored", vbOKCancel + vbInformation) = vbOK Then
Application.EnableEvents = False
Worksheets("User").Range("E19:I3018").ClearContents
Application.EnableEvents = True
Else
Exit Sub
End If
End Sub
That is, you have to suppress the Change event in other macros working on that sheet. Not elegant but doable.
To clarify what the first macro does: it saves the cell's content, undoes a user's paste or input, and then only fills in the value which was pasted, leaving the format intact. The problem with this approach is that the event handler does not return information on the action that triggered it - it could be a paste but clearing cells as well.
You can only use .Undo to undo the last action in the worksheet not to undo vba actions and must be the first line in the macro. As explained in the documentation.Application.Undo. Quote below:
This method undoes only the last action taken by the user before
running the macro, and it must be the first line in the macro. It
cannot be used to undo Visual Basic commands.

Disable checkboxes when sheet opened in vba

I have 3 checkboxes. When a user opened my sheet, he/she must not check checkboxes. I want them to be disabled. How can I do that?
Not sure if you meant ActiveX or FormControl, so here you go
Code
Private Sub Worksheet_Activate()
Dim myActiveX As Object
Set myActiveX = Sheet1.OLEObjects("CheckBox1")
myActiveX.Object.Value = True
myActiveX.Object.Locked = False ' Make it False if you wish to enable it
myActiveX.Object.Enabled = False ' Another option to disable
Dim myFormControl As CheckBox
Set myFormControl = ActiveSheet.Shapes("Check Box 1").OLEFormat.Object
myFormControl.Value = True
myFormControl.Enabled = False ' Make it True if you wish to enable it
End Sub
Live GIF demo
You have to write some VBA code in order to do that.
Let's suppose that you have 3 CheckBoxes in your first sheet.
By holding the "Alt" key on your keyboard and the pressing one time the "F11" key, opens Microsoft Visual Basic. ( Alt + F11 )
At your left hand you can see the "VBAProject" tree.
Double click on the "ThisWorkbook" file and copy the following code in the window it will appear:
Private Sub Workbook_Open()
void = uncheckAllCheckboxes()
End Sub
Function uncheckAllCheckboxes()
ThisWorkbook.Worksheets(1).CheckBox1.Value = False
ThisWorkbook.Worksheets(1).CheckBox2.Value = False
ThisWorkbook.Worksheets(1).CheckBox3.Value = False
End Function
Save the excel file as "Excel 97-2003 Workbook" type (.xls)
Close your excel.
Open the file you have previously saved and everything will work fine.
;)
P.S.: It is important to enable macros from your excel settings

VBA Excel: Moving data macro error on protected sheets

I have the following example code in a module of VBA:
Sub My_Code()
ThisWorkbook.Sheets("Main").Range("A1") = "Main Data"
ThisWorkbook.Sheets("Secondary").Range("A2").Copy Sheets("Main").Range("B2")
End Sub
and to protect the sheets, Main and Secondary, I have put the following code in Thisworkbook of VBA:
Private Sub Workbook_Open()
Sheets("Main").Protect Password:="Mypassword", UserInterfaceOnly:=True
Sheets("Secondary").Protect Password:="Mypassword", UserInterfaceOnly:=True
End Sub
When I run My_Code() I get the error:
""Run-time error '1004'
The cell or chart you're trying to change is on a protected sheet.
To make changes, click Unprotect Sheet in the Review tab (you might need a password).""
And this debugs to the ThisWorkbook.Sheets("Secondary").... line.
When I manually Unprotect the Main sheet the code runs. Any ideas why I can't leave Main protected? Have I forgotten something?
#jkpieterse Gave the solution to this question which was to change the second line of the My_Code() to
Thisworkbook.Sheets("Main").Range("B2").Value = ThisWorkbook.Sheets("Secondary").Range("A2").Value
However this created a new error in my code which is mentioned in the comments about. The who reason behind this problem is that the UserInterfaceOnly = true does not allow macros to modify the sheet, it only allows for value changes. Therefore there is no way to use the interface protect work around when you modify the worksheet. The only solution from here is:
Sub My_Code()
Dim ws as Worksheet
Set ws = ThisWorkbook.Sheets("Main")
ws.UnProtect Password:="Mypassword"
On Error GoTo ErrHandeler
ws.Range("A1") = "Main Data"
ThisWorkbook.Sheets("Secondary").Range("A2").Copy ws.Range("B2")
ws.Protect:="Mypassword"
ErrHandler:
ws.Protect:="Mypassword"
End Sub
This is the next most secure solution.
The cells that you want to populate data in or modify needs to be unlocked. So select the range of cells, then in format cell set them to be unlocked. When you password protect the sheet, make sure you check allow to edit unlocked cells.
Try this with you original code, it should work. Since it worked when you unprotected the sheet.
It appears you have to reset the protection with UserInterfaceOnly = True upon Workbook_Open, which resolves my issue. Excel closes the workbook with a default of UserInterfaceOnly = False (even though I run the secure commands on the Workbook_BeforeClose event.