I am facing a complication with excel macro syntax.
My workbook contains several sheets, with the first one titled "Reference Sheet".
There are some entries in the other sheets that I do not want the user to edit through the sheet they are currently working on but only through the Reference Sheet.
I locked the cells and used protect sheet, however I want the user to receive a prompt message whenever they double click on one of the cells in the concerned range, asking them if they want to change the selected cell but in the Reference Sheet.
My aim is to have the same cell selected in the current sheet, selected in the Reference Sheet to be able to edit it.
I posted the following code in the corresponding sheet VB but apparently there is an error in the Cells property at the end -> Cells(val1, val2).Select
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Intersect(Target, Range("C2:C5,E2")) Is Nothing Then
Else
Dim Msg As String, Title As String
Dim Config As Integer, Ans As Integer
Msg = "Do not modify this entry from the current sheet."
Msg = Msg & vbNewLine
Msg = Msg & "This modification is only enabled in the Reference Sheet."
Msg = Msg & vbNewLine
Msg = Msg & "Would you like to go to the corresponding cell and modify it?"
Title = "Attention"
Config = vbYesNo + vbExclamation
Ans = MsgBox(Msg, Config, Title)
If Ans = vbYes Then
Dim val1 As Integer, val2 As Integer
val1 = ActiveCell.Row
val2 = ActiveCell.Column
Worksheets("Reference Sheet").Activate
Cells(val1, val2).Select
End If
End If
End Sub
Your thoughts are much appreciated.
The reason your code fails is that in a Worksheet module an unqualified range reference (Cells(val1, val2) in your case) refers to the worksheet Module, not the Active worksheet. Since you have just activated another sheet, you are trying to select a cell on an inactive sheet, which causes the error.
A better way to do it is
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Intersect(Target, Range("C2:C5,E2")) Is Nothing Then
Else
Dim Msg As String, Title As String
Dim Config As Long, Ans As VbMsgBoxResult
Msg = "Do not modify this entry from the current sheet."
Msg = Msg & vbNewLine
Msg = Msg & "This modification is only enabled in the Reference Sheet."
Msg = Msg & vbNewLine
Msg = Msg & "Would you like to go to the corresponding cell and modify it?"
Title = "Attention"
Config = vbYesNo + vbExclamation
Ans = MsgBox(Msg, Config, Title)
If Ans = vbYes Then
With Worksheets("Reference Sheet")
.Activate
.Range(Target.Address).Select
End With
End If
End If
End Sub
Related
I've code with a delete button that deletes a row according to the user's choice.
I want to restrict the user from deleting a specific row or Range (equivalent to the line).
Private Sub Deletar_Click()
Dim answer As VbMsgBoxResult, tbl As ListObject, error As VbMsgBoxResult
answer = MsgBox("You want to proceed with the delete?", vbYesNo + vbQuestion, "Excluir Linha"):
If answer = vbYes & Range.Row(2).Select Then
error = Msgbox("You cant delete this row",vbCritical+vbRetryCancel,"Error")
If answer <> vbYes Then Exit Sub
Set tbl = MySheet.ListObjects("DataTable")
tbl.DataBodyRange.Rows(Range.Row - tbl.DataBodyRange.Row).Delete
End Sub
I end up getting the following error:
Wrong number or arguments or...
EDIT: split out the logic for figuring out what listobject row is selected.
Maybe like this:
Sub Deletar_Click()
Dim rw As ListRow
Set rw = SelectedListRow(Selection, mySheet.ListObjects("DataTable"))
If rw Is Nothing Then 'make sure a row in the data table has been selected
MsgBox "First select one or more cells in the data row to be deleted"
ElseIf rw.Index = 1 Then 'first row can't be deleted
MsgBox "The first row cannot be deleted", vbExclamation
Else
'OK to deelte on user confirmation
If MsgBox("Delete selected row?", vbYesNo + vbQuestion, "Excluir Linha") = vbYes Then
rw.Delete
End If
End If
End Sub
'Given a Range and a ListObject, return a ListRow corresponding to `rng` (or Nothing
' if rng is noth within the listobject's DatabodyRange
Function SelectedListRow(rng As Range, tbl As ListObject) As ListRow
Dim sel As Range, rowIndex As Long
If Not rng.Parent Is tbl.Parent Then Exit Function 'on different sheets...
Set sel = Application.Intersect(rng.Cells(1), tbl.DataBodyRange) 'only check top-left cell of `rng`
If Not sel Is Nothing Then
rowIndex = 1 + (sel.Row - tbl.DataBodyRange.Cells(1).Row) 'which table row is selected?
Set SelectedListRow = tbl.ListRows(rowIndex)
End If
End Function
I recently found a macro to delete hidden names in a given workbook.
What I'd like to add to it is a pop up window that would first display how many names there are, and a yes no button for running it. Just to give the user an idea of how long the function will take to run if they choose to run it.
This is the code as is:
Dim RangeName As Name
On Error Resume Next
For Each RangeName In Names
ActiveWorkbook.Names(RangeName.Name).Delete
Next
On Error GoTo 0
End Sub
Try this:
Sub test()
Dim RangeName As Name
Dim answer As Integer
Dim str As String
On Error Resume Next
str = "Do you want to delete " & ActiveWorkbook.Names.Count & " names?"
answer = MsgBox(str, vbQuestion + vbYesNo + vbDefaultButton2, "Message Box Title")
If answer Then
For Each RangeName In Names
ActiveWorkbook.Names(RangeName.Name).Delete
Next
Else
Exit Sub
End If
On Error GoTo 0
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 have the following code that simply delete the range in excel.. but I don't know why that if you click the button to delete the selected range it happens the entire range are deleting and I don't know why. Can you help me thanks in advance
Private Sub cmdDel_Click()
cmdEdit.Enabled = False: cmdAdd.Enabled = False
cmdClose.Caption = "CANCEL"
If MsgBox("Delete this record?", vbYesNo + vbQuestion, "Message") = vbYes Then
Range("A" & r & ":" & "V" & r).Delete
r = 0
MsgBox "Record deleted!", vbExclamation, "Message"
End If
Call UserForm_Activate
End Sub
It's simple because the value of r is 0 so your string actually becomes
Range("A:V").Delete
Set a value of r before deleting and the problem will go away
Also if you are manually selecting the range and deleting the range then use this
Selection.Delete
I've used the 'protection worksheet' option in Excel but in addition, I 'd like to ask the user to input a password upon clicking on each sheet. There's a specific password per sheet. If you don't know the password, I don't want the user to be able to modify anything on the sheet. They can print but can't modify anything. I have a password per sheet but the code I'm using isn't working...Maybe it's too basic...Can someone please assist?
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim Msg As String
Dim UserEntry As Variant
Msg = InputBox("What is the password?")
Do
Sheet1.Activate
UserEntry = InputBox(Msg)
If UserEntry = "test" Then Exit Sub
If UserEntry = False Then
Msg = "Invalid Password!"
Msg = Msg & vbNewLine
Msg = Msg & "What is the password?"
Loop
Sheet1.Activate = UserEntry
End Sub
Although it might depend on your version of Excel (I tested in 2007), just right-click the tab and select "Protect Sheet". You can set a password for each sheet seperately.
A user will just go to the Review tab in the ribbon and select "Unprotect sheet" and enter the password.
You really want to avoid setting passwords via VBA since it's really easy to go into the code to find the password.
Here's the basics, you can add back the check for an invalid password.
Private Sub Worksheet_Activate()
Dim Msg As String
Dim UserEntry As String
Msg = InputBox("What is the password?")
If Msg = "test" Then
ActiveSheet.Unprotect ("password")
End If
End Sub
try this in ThisWorkbook module
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
On Error GoTo WrongPassword
Sh.Unprotect
CleanUp:
Exit Sub
WrongPassword:
MsgBox "Wrong Password"
End Sub