We are currently trying to get the encryption macro to work on multiple cells throughout the workbook, I have a lot going on with some of these cells so I am open to anything to make this flow better. Currently, the macro is under our finalize form button. This is the coding on sheet 1, the function code is under "this workbook"
When we try running this under other worksheet_selectionchange(ByVal target As Range) code, it doesn't allow the text box (got_focus) code to run on the cell.
I've tried changing the location of the code whether its in its own sub or being called to with a button and I'm unable to get this to correct itself. the cell that is in range is merged and would be ("B23:D23"), but making that change didn't change my debug error.
Private Sub FINALIZEBTN_Click()
Dim response As VbMsgBoxResult
response = MsgBox("Have you completed the form in full?", vbYesNo)
If response = vbYes Then
MsgBox "Do not forget to save and submit this form"
ElseIf response = vbNo Then
MsgBox "Please review and complete the form in full"
Exit Sub
End If
Dim searchRange As Excel.Range
Dim cell As Variant
Dim RegEx As Object
Set RegEx = CreateObject("VBScript.RegExp")
With RegEx
.Pattern = "[^ :#a-zA-Z0-9&\-]+"
.Global = True
.MultiLine = True
End With
Set searchRange = ActiveSheet.Range("B18:E52") '// Change as required
For Each cell In searchRange.Cells
If RegEx.Test(cell) Then cell.value = RegEx.Replace(cell.value, "")
cell.value = UCase(cell.value)
Next cell
Set searchRange = Nothing
Set RegEx = Nothing
'ENCRYPTION MACRO
Dim KeyCells As Range
Set KeyCells = Range("B23")
Dim publicKey As String
publicKey = "<RSAKeyValue><Modulus>r2+QhdQrh+jlSz/F2f9TyfVbar79NUHqiQby7paaUB5pejiYg/aI8on642s0FYNiiASSqK81+ORA9BXS0AHMnnkyplWZ7B2/KnrmFb3Ujoemzb794MpmUxtztrAocmIepJwsuShBQD2eUvCzNKI8aLcgH9mDGuG/HvagHCyzbyfV+yPtMGIHY2W1qboFGGvisAgVGjUgUAzpsqbuHiP1muohr5yKRmeyTwZmjEeWY/OuoX5zyDvjd0jsCw8GiNzkPqb6qCZR8KXSZNcyZnf4NbjR/dOD5qeEwFZWY32LmGFQW4GVOUfaIStvRwXq1G7k5oPXb6ccAhDtlrieM9l65p0X9alGYfTvLel4SBRRMqc8icadJq4KXTh1qRwp7w6uJUnd90GqfMXo1Qqyjwuqre0BBro/e3/BH8BorWynby3JAD5GNnBrB/RX9y/DFobNHXV9vtNhMTBMhCfSMhJQNlnH8nT3jcdvydbWEpNuJt3EKoCiOQlRXyv+bBL2sVTSzdCV4cWj7CfX5ZVCaliBu4nybqWOszZyQJqCHZCgnPj2Pww7wHkFUHqngiKdK6T45IkcdohLS8AU+zCUD9K6R6qTBG1S8JKkmEfuBhNx+uWMU0fwEL6ThhUmUAqZAm7MBKxnBkR+yoT5zsHoi3aYYi9sF7Opw+acqtY9zqi/OA0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>" 'put entire xml string here
If Not Application.Intersect(KeyCells, Range(target.Address)) Is Nothing Then
Application.EnableEvents = False
If VarType(Range(target.Address).value) <> 8204 Then
If Len(Range(target.Address).value) < 256 Then 'making sure that encry sting isnt previously encrypted
Range(target.Address).value = ThisWorkbook.Encrypt(publicKey, CStr(Range(target.Address).value))
Range(target.Address).HorizontalAlignment = -4108 'XLALIGNCENTER
End If
Else
Range(target.Address).HorizontalAlignment = -4131 'XLALIGNLEFT
End If
Application.EnableEvents = True
End If
End Sub
The line
If Not Application.Intersect(KeyCells, Range(target.Address)) Is Nothing Then causes the run-time error 424 object required pop up.
Related
I would like to develop a code where I can have a dropdown list of sheet names which I want to unhide with a password. I have tried a lot but got no success.
Suppose, I have a multiple sheets by names, "A", "B", "C", up to "F". When I select one or multiple sheet names from dropdown box, it should prompt for password to unhide sheet. Please suggest the best way to do so.
Private Sub Worksheet_Change(ByVal Target As String)
Dim Target As String, msg As Variant
Set Target = Sheets("Sheet1").Range("A1")
If Target.Visible = False Then
msg = Application.InputBox("Password", "Password", "", Type:=2)
If response = "pgdb" Then
Target.Visible = True
Target.Select
Else
Target.Visible = False
End If
End Sub
Thanks. Made below changes in code, but getting Error 9 "Subscript out of range" after assigning the value to Target variable. Please advise.
'Private Sub Worksheet_Change(ByVal Target As Range)
Dim msg As Variant, sh As Range
Target = Sheets("Sheet32").Range("A1")
sh = Target.Value
If Application.ActiveSheet.Name = sh Then
Application.EnableEvents = False
Application.ActiveSheet.Visible = False
msg = Application.InputBox("Password", "Password", "", Type:=2)
If msg = "pgdb" Then
Application.sh.Visible = True
Application.sh.Select
Else
Application.sh.Visible = False
End If
End If
Application.EnableEvents = True
End Sub
It would look something like below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim DropDownCell As Range
Set DropDownCell = Me.Range("A1") 'me points to the workbook the code is written in
If Not Intersect(DropDownCell, Target) Is Nothing Then 'run the following only if the DropDownCell is part of (intersects) with the changed cells (Target)
Dim PasswordInput As Variant
PasswordInput = Application.InputBox("Password", "Password", "", Type:=2)
If PasswordInput = "pgdb" Then
Dim SheetToUnhide As Worksheet
On Error Resume Next 'next line throws error if sheet does not exist. Hide all error messages from now.
Set SheetToUnhide = ThisWorkbook.Worksheets(DropDownCell.Value)
On Error Goto 0 're-enable error reporting (or you won't notice any further errors if they occur.
'note that SheetToUnhide is Nothing here if the workbook with the name of the drop down value does not exist.
If Not SheetToUnhide Is Nothing Then 'sheet exists
SheetToUnhide.Visible = True
SheetToUnhide.Select
Else 'sheet does not exist
MsgBox "Sheet '" & DropDownCell.Value & "' does not exist.", vbCritical
End If
End If
End If
End Sub
Note that this procedure Private Sub Worksheet_Change(ByVal Target As Range) runs every time any cell gets changed in the worksheet. Target reprecents cell that was changed. Note that Target is a Range and can be multiple cells (if multiple cells get changed at the same time eg. by copy/paste).
This line If Not Intersect(DropDownCell, Target) Is Nothing Then makes sure the code runs only if the drop down cell was changed, and not on every cell change.
I have two columns, I & Q, both with formulas in them. If the formula in Q returns an error, I want to unlock the cell in column I of that row. Here's what I have and it doesn't work:
Private Sub UnlockError(ByVal Target As Range)
Application.EnableEvents = False
If Intersect(Target, Sheet2.Range("Q:Q")) Is Nothing Then GoTo ResetEvents
If IsError(Target) Then
ActiveSheet.Unprotect Password:="#Pentagon2020"
Target.Offset(0, -8).Locked = False
ActiveSheet.Protect Password:="#Pentagon2020"
End If
ResetEvents:
Application.EnableEvents = True
End Sub
The error that triggers the unlocking of another cell must be within a procedure, as demonstrated in the Change event procedure below.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim MyError As Double
If Not Application.Intersect(Target, Range("A:A")) Is Nothing Then
On Error Resume Next
MyError = 100 / 0
If Err.Number = 11 Then
With Cells(Target.Row, "B")
.Locked = False
.Select
End With
ElseIf Err.Number Then
MsgBox "An unidentified error occurred.", _
vbInformation, "Error messsage"
Else
' continue with your program
Target.Value = MyError
End If
End If
End Sub
If you want your procedure to look at a cell and determine if it contains an error this code will do it.
If IsError(Cells(2, "A") Then
With Cells(2, "B")
.Locked = False
.Select
End With
End If
The problem with this code is that you would either need a button to call it or embed it in another procedure that is called by pressing a button.
Worksheet_Calculate
The following is a rather un-efficient solution. It will be triggered each time the worksheet gets calculated i.e. a change will happen 'due to' a formula. It will first lock all cells in the Lock Range and then unlock the desired ones. If you don't have thousands of rows, this may serve you well.
A better solution may be to to write all the values in the Source Range to a public array to keep track of the changes. Then each time the worksheet is calculated, the values of a new array would be checked against the values in the public array. Appropriate changes would be made, and in the end the new array would be written to the public array. Keep in mind that the first writing of the public array could be done by using the Workbook_Open event and that rows may get added or deleted.
The best solution, if possible, would be to steer this whole operation towards the Worksheet_Change event i.e. trace back the formulas to the cells that are changed manually or via VBA and are 'causing' the resulting error values. Then checking only the values that got changed would increase efficiency. Keep in mind that in this event Application.EnableEvents is often necessary and should be 'accompanied' by error handling.
Adjust the values in the constants section.
Standard Module e.g. Module1
Option Explicit
Sub unlockErrorValuesInit( _
ws As Worksheet)
Const sFirst As String = "Q2"
Const lFirst As String = "I2"
Const MyPassWord As String = "" '"#Pentagon2020"
unlockErrorValues ws.Range(sFirst), ws.Range(lFirst), MyPassWord
End Sub
Sub unlockErrorValues( _
srcFirstCell As Range, _
lockFirstCell As Range, _
Optional ByVal MyPassWord As String = "")
' Validate inputs.
If srcFirstCell Is Nothing Then Exit Sub
If lockFirstCell Is Nothing Then Exit Sub
' Calculate offsets.
Dim rOffs As Long: rOffs = lockFirstCell.Row - srcFirstCell.Row
Dim cOffs As Long: cOffs = lockFirstCell.Column - srcFirstCell.Column
' Define Source (Column) Range.
Dim srg As Range
With srcFirstCell
Set srg = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If srg Is Nothing Then Exit Sub
Set srg = .Resize(srg.Row - .Row + 1)
End With
Application.ScreenUpdating = False
srg.Worksheet.Unprotect MyPassWord
' Reset Lock (Column) Range (lock all cells).
With srg.Offset(rOffs, cOffs)
.Locked = True
.Interior.Color = xlNone ' to better visualize
End With
' Define Destination Range of Source Range (cells containing error values).
On Error Resume Next
Dim drg As Range: Set drg = srg.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
' Unlock cells in Destination Range of Lock Range.
If Not drg Is Nothing Then
With drg.Offset(rOffs, cOffs)
.Locked = False
.Interior.Color = vbYellow ' to better visualize
End With
End If
srg.Worksheet.Protect MyPassWord
Application.ScreenUpdating = True
End Sub
Sheet Module e.g. Sheet1 (the name in parentheses in the VBE Project Explorer)
Option Explicit
Private Sub Worksheet_Calculate()
unlockErrorValuesInit Me
End Sub
I'm trying to write a code to trace every change made by the user on any worksheet. The user will input data and from time to time will erase said data and/or correct the original value they inserted. If the change is either deletion or modification, an Userform will pop up and the user will include a reason for that change. Right now I'm able to display the form everytime the user makes one of the changes mentioned before, but I'm not able to retrieve the reason, could you guys help me?
This is what I have for the UserForm
Private Sub CommandButton1_Click()
Dim msgvalue As VbMsgBoxResult
Dim value As String
msgvalue = MsgBox("Do you wish to save the change?", vbYesNo + vbInformation, "Confirm")
If msgvalue = vbNo Then GoTo Command
If msgvalue = vbYes Then
value = UserForm1.txtCmmt.Value
If value = "" Then GoTo Command
End
End If
Command:
MsgBox ("A reason must be provided")
With UserForm1
.txtCmmt.Value = ""
End With
End Sub
So if a user tries to delete a value, the code is the following:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim sLastAction As String
Dim Cell As Range
sLastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
For Each Cell In Target
If sLastAction = "Clear" Or sLastAction = "Delete" Or Left(sLastAction, 9) = "Typing ''" Then
UserForm1.Show 'this is where I'm stuck, I'm not sure how to retrieve the value from the form
End If
'the code continues to retrieve other info from the changes made, including the "reason"
Thanks for the help!
Try the next way, please:
Let us say that your text box where the comment will be written is named "txtComment".
Put this code in its Exit event:
Private Sub txtComment_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Me.txtComment.text <> "" Then
If ActiveSheet.Name <> "LogDetails" Then
Application.EnableEvents = False
Sheets("LogDetails").Range("A" & rows.count).End(xlUp).Offset(0, 5).Value = Me.txtComment.text
Application.EnableEvents = True
Unload Me
End If
End If
End Sub
Let the existing Worksheet_Change event as it is, only launching the form and maybe making a Public boolean variable (from a standard module) True (something boolStop) which will not allow changing anything in any worksheet until it is not False.
Then fill the text you need in the text box ("txtComment", or however you named it) and press Enter. If my above suggestion looks interesting for you, the last line of the text box event will be boolStop = False.
If you understand how to implement the above simple solution, you maybe will forget about a user form and use a simple InputBox, as in the next example:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address(0, 0) <> "E1" Then Exit Sub
Dim sLastAction As String, comValue As String
Dim Cell As Range
sLastAction = Application.CommandBars("Standard").Controls("&Undo").list(1)
For Each Cell In Target
If sLastAction = "Clear" Or sLastAction = "Delete" Or left(sLastAction, 9) = "Typing ''" Then
WritePlease:
comValue = InputBox("Please write the reason for cell """ & Cell.Address & """ (" & sLastAction & ").", "Reason, please")
If comValue = "" Then GoTo WritePlease
If ActiveSheet.Name <> "LogDetails" Then
Application.EnableEvents = False
'Stop
Sheets("LogDetails").Range("A" & rows.count).End(xlUp).Offset(0, 5).Value = comValue
Application.EnableEvents = True
End If
End If
Next
End Sub
I want to clear the contents of the cell after clicking the ok button in a message pop up window.
When the pop up window disappears, after clicking ok button umpteen times, the script terminates by throwing the below error
Run time error '-2147417848(80010108)':
Method 'Range of object'_Worksheet'Failed
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = Range("N4:O4")
If Not Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
If (Range("E9") = "" Or Range("F9") = "") Then
MsgBox "Reopen Date and Closed Date should not be populated before calculating the Benefit Begin Date and Maximum Benefit Date"
Sheets("Calculation Tool").Range("N4").Clear ----->Code written to clear the cells
Else
If (Range("N4") = "" Or Range("O4") = "") Then
Set b1 = Sheets("Calculation Tool").CommandButton22
b1.Enabled = False
Else
Set b1 = Sheets("Calculation Tool").CommandButton22
b1.Enabled = True
End If
End If
End If
End Sub
I wanted to tell #BigBen that his suggestion worked for me, but my low rep won't allow me to comment. The answer field is the only way of expression for me!
So I might as well formulate a valid answer, here it goes. :)
So I had the same problem within a Worksheet_Change event macro, in this casual event macro:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeToCheck As Range
Set RangeToCheck = ActiveSheet.Range("O3:O32")
(above is the line that triggered randomly that Run time error '-2147417848(80010108)' you encountered; on with the script)
If Not Application.Intersect(Target, RangeToCheck) Is Nothing Then
Target.Value = VBA.Replace(Target.Value, ".", ",")
Debug.Print Target.Address, Target.Value
Else
Debug.Print "Not in RangeToCheck"
End If
End Sub
Following BigBen's link, I found that the following code works fine :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeToCheck As Range
On Error GoTo enableEventsOn:
Application.EnableEvents = False
Set RangeToCheck = ActiveSheet.Range("O3:O32")
Application.EnableEvents = True
On Error GoTo 0
If Not Application.Intersect(Target, RangeToCheck) Is Nothing Then
Target.Value = VBA.Replace(Target.Value, ".", ",")
Debug.Print Target.Address, Target.Value
Else
Debug.Print "Not in RangeToCheck"
End If
enableEventsOn:
Application.EnableEvents = True
End Sub
I am trying to prevent pasting over a dropdown in Excel. The code I came up with is the following:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
'turn off events so this routine is not continuously fired
Set BoroughTrainingTookPlaceIn = Range("BoroughTrainingTookPlaceIn")
Set StartTimeOfSession = Range("StartTimeOfSession")
Set TypeOfSession = Range("TypeOfSession")
Set BikeabilityLevelRatingBeforeTraining = Range("BikeabilityLevelRatingBeforeTraining")
Set BikeabilityLevelRatingAfterTraining = Range("BikeabilityLevelRatingAfterTraining")
If RangesIntersect(Target, BoroughTrainingTookPlaceIn) Then
PreventPaste (BoroughTrainingTookPlaceIn)
ElseIf RangesIntersect(Target, StartTimeOfSession) Then
PreventPaste (StartTimeOfSession)
ElseIf RangesIntersect(Target, TypeOfSession) Then
PreventPaste (TypeOfSession)
ElseIf RangesIntersect(Target, BikeabilityLevelRatingBeforeTraining) Then
PreventPaste (BikeabilityLevelRatingBeforeTraining)
ElseIf RangesIntersect(Target, BikeabilityLevelRatingAfterTraining) Then
PreventPaste (BikeabilityLevelRatingAfterTraining)
End If
Application.EnableEvents = True
End Sub
Private Function HasValidation(r) As Boolean
' Returns True if every cell in Range r uses Data Validation
On Error Resume Next
x = r.Validation.Type
If Err.Number = 0 Then HasValidation = True Else HasValidation = False
End Function
Function RangesIntersect(ByVal Range1 As Range, ByVal Range2 As Range) As Variant
Dim intersectRange As Range
Set intersectRange = Application.Intersect(Range1, Range2)
If intersectRange Is Nothing Then
RangesIntersect = False
Else
RangesIntersect = True
End If
End Function
Private Function PreventPaste(ByVal Target As Range) As Variant
If Not HasValidation(Target) Then
Application.Undo
MsgBox "Invalid value. Please chose a value from the dropdown"
End If
End Function
The line x = r.Validation.Type is causing Error 1004 when I try to copy by dragging a cell in the dataValdiation Range. I am using named ranges.
I looked trough the already opened questions but didn't find answer there. All help is greatly appreciated.
EDIT:
I was trying to cut it and not to copy and paste it by dragging. Still for newbies like me might be useful to record the macro first and see what you are actually doing