how to retrieve a value from an userform - excel

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

Related

How to run this function in excel using vba

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = Range("B12").Address Then
Application.EnableEvents = False
Dim sOldValue As String, sNewValue As String
sNewValue = Target.Value
Application.Undo
Dim rOld As Range
Set rOld = Range("A1:E1").Value
Target.Value = sNewValue
Range("A15:E15").Value = rOld.Value
Application.EnableEvents = True
End If
End Sub
How to run this function, can you please call this function?
Create a button, add in the following code, you might need to change your code from Private to Public
`Private Sub CommandButton1_Click()
Call Worksheet_Change
End Sub`
The code you posted is for the Worksheet.Change event. The event occurs when cells on the worksheet are changed by the user or by an external link.
All you need to run this sub is to place the code in the sheet module for the relevant sheet and change B12 cell.
A Worksheet Change: Change Range Values on Cell Change
Worksheet_ in the signature Private Sub Worksheet_Change(ByVal Target As Range) indicates that this procedure belongs in the sheet module, e.g. Sheet1, of the worksheet where you want it applied (not in the ThisWorkbook module nor in a standard module, e.g. Module1). Such a procedure will run automatically (get triggered) when an event occurs, particularly for this procedure, after a manual change has happened in a range i.e. after
you write something into the formula bar and press enter,
you (copy) paste values to a range, or
you use VBA to write values to a range.
In this procedure, if you want to write something to a range of the worksheet, to not retrigger the event and possibly end up with an endless loop ('crashing' Excel), you will disable events before you start writing, and enable them after writing as you did in your code. If an error occurs between these two lines, the events will stay disabled and the code won't trigger until they are enabled again.
To check if events are enabled you could use the line Debug.Print Application.EnableEvents in another procedure or in the Immediate window just use ?Application.EnableEvents and press enter. Similarly, if the answer is False, in the Immediate window, you can use Application.EnableEvents = True and press enter to enable events.
The line Set rOld = Range("A1:E1").Value is wrong and results in
Run-time error '424': Object required
To avoid the error you could use one of the following:
Dim rgOld As Range: Set rgOld = Range("A1:E1")
Range("A15:E15").Value = rgOld.Value
Target.Value = sNewValue
Dim OldValues() As Variant: OldValues = Range("A1:E1").Value
Range("A15:E15").Value = OldValues ' or after the following line
Target.Value = sNewValue
Range("A15:E15").Value = Range("A1:E1").Value
Target.Value = sNewValue
Basically, you want to write the data before rewriting the new value. Optionally, in the second case where the data is written to an array (OldValues), you can write the values afterward.
Since the use of an additional variable is kind of redundant in the first two cases, the last (the simplest, the most straightforward) case is used in the following code.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address <> "$B$12" Then Exit Sub
Dim NewString As String: NewString = CStr(Target.Value)
Application.EnableEvents = False
Application.Undo ' this will also write (trigger the event)
Me.Range("A15:E15").Value = Me.Range("A1:E1").Value
Target.Value = NewString ' redo
Application.EnableEvents = True
End Sub
If you want to modify (experiment with) the code, you should introduce some error handling so you don't end up with events disabled.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ClearError
If Target.Address <> "$B$12" Then Exit Sub
Dim NewString As String: NewString = CStr(Target.Value)
Application.EnableEvents = False
Application.Undo ' this will also write (trigger the event)
Me.Range("A15:E15").Value = Me.Range("A1:E1").Value
Target.Value = NewString ' redo
SafeExit:
On Error Resume Next
If Not Application.EnableEvents Then Application.EnableEvents = True
On Error GoTo 0
Exit Sub
ClearError:
Debug.Print "Run-time error'" & Err.Number & "': " & Err.Description
Resume SafeExit
End Sub
One thing is basic: how did you create this function? Did you open the Excel VBA editor, select a sheet and chose the corresponding event, like I did in the following screenshot:
As you see, the macro is linked to "Sheet1", it is linked to the events of the "Worksheet" itself, and it is triggered by any "Change" of that worksheet.

Hide Entire given rows if a specified cell is blank

I am a newbie in VBA coding.
I am trying to achieve that inside my function
sub Private Sub Worksheet_Change(ByVal Target As Range)
where it checks some specified cells value change to run a given macro. The additional macro that i want to add is that when ever cell a62 is Empty, it will hide rows a56:a61. and consecutively if a82 is empty, it will hide rows a78:a82.
i have the following code but it only hides the rows from the first empty cell until end of sheet.
Sub Test()
Dim i As Long
For i = 4 To 800
If Sheets("Results").Cells(i, 1).Value = "" Then
Rows(i & ":" & Rows.Count).EntireRow.Hidden = True
Rows("1:" & i - 1).EntireRow.Hidden = False
Exit Sub
End If
Next
End Sub
Please, check the next event code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$62" Or Target.Address = "$A$82" Then
Select Case Target.Address
Case "$A$62"
If Target.Value = "" Then
Range("A56:A61").EntireRow.Hidden = True
Else
Range("A56:A61").EntireRow.Hidden = False
End If
Case "$A$82"
If Target.Value = "" Then
Range("A78:A81").EntireRow.Hidden = True
Else
Range("A78:A81").EntireRow.Hidden = False
End If
End Select
End If
End Sub
It will be triggered only if you MANUALLY change the value of one of the two required cells.
If their value is the result of a formula, Worksheet_Calculate event must be used, but in a different way. This event does not have any argument (no Target) and you must check the two cells in discussion and act according to their value, independent if they were changed or not when the Calculate event is triggered. If this is the case, I can post such an event code, too.
Edited:
For the version which does not involve the manual changing of the values, please copy this event code in the sheet code module:
Private Sub Worksheet_Calculate()
If Me.Range("A62").Value = "" Then
Me.Range("A56:A61").EntireRow.Hidden = True
Else
Me.Range("A56:A61").EntireRow.Hidden = False
End If
If Me.Range("A82").Value = "" Then
Me.Range("A78:A82").EntireRow.Hidden = True
Else
Me.Range("A78:A82").EntireRow.Hidden = False
End If
'Edited:
'The part for both analyzed ranges being empty:
If Me.Range("A62").Value = "" And _
Me.Range("A82").Value = "" Then
'Do here what you need...
End If
End Sub

Excel Userform to update existing Data

I would like to overwrite data using a Userform, I can call the data to the form based on a Combobox (unique reference from column A in my data sheet). I am failing to send updated data back, and am stuck on a Run-time error '13.
I have looked at a number of posts but cannot pick out a thread to success! Any help appreciated. I have left the code simple, to update the 4 column of that row. Ultimately I will expand from the 2nd column onwards.
Private Sub cmbtrade_Change() - this part works as expected
Dim trade_name As String
If Me.cmbtrade.Value = "" Then
MsgBox "Trade Can Not be Blank!!!", vbExclamation, "Trade"
Exit Sub
End If
trade_name = cmbtrade.Value
On Error Resume Next
Dim trade As Double
trade_name = cmbtrade.Value
TextBox16.Text = Application.WorksheetFunction.VLookup(trade_name,
Sheets("Sheet2").Range("A2:D43"), 4, False)
End Sub
The problem part....
Private Sub cmdupdate_Click()
If Me.cmbtrade.Value = "" Then
MsgBox "Trade Name Can Not be Blank", vbExclamation, "Trade"
Exit Sub
End If
trade_name = cmbtrade.Value
Sheets("sheet2").Select
Dim rowselect As Double
rowselect = Me.cmbtrade.Value (this is where my mismatch error occurs)
rowselect = rowselect + 1
Rows(rowselect).Select
Cells(rowselect, 4) = Me.TextBox16.Value
End Sub
enter image description here
Try this. You don't actually need to convert the combobox to a Long, but it's good practice I think.
Private Sub cmdupdate_Click()
If Me.cmbtrade.Value = "" Then
MsgBox "Trade Name Can Not be Blank", vbExclamation, "Trade"
Exit Sub
End If
Dim rowselect As Long
rowselect = CLng(Me.cmbtrade.Value) + 1
Sheets("sheet2").Cells(rowselect, 4) = Me.TextBox16.Value
End Sub

VBA - Undo ComboBox change

I cannot seem to get this code to work... I am trying to basically say, if the combo box changes and the range is not empty ask if the user really does want to clear the range and make the change. If they say no, then undo the combobox change back to what it was. My options for the Sub do not display a BeforeUpdate, only the Change and some others.
I tried to capture the value beforehand and set it back to that, but it doesnt work.
Any ideas welcome!!
Sub ComboBox_UPC_C18_Change()
Dim ComboBox_UPC_C18_Value As String
Dim Location As Range
Set Location = Range("Location_C18")
If Application.WorksheetFunction.CountA(Location) = 0 Then
Exit Sub
ElseIf MsgBox("Are you sure you want change the UPC (clearing the row's data)?", vbYesNo, "User Confirmation") = vbYes Then
Location.Value = ""
ElseIf MsgBox("Are you sure you want change the UPC (clearing the row's data)?", vbYesNo, "User Confirmation") = vbNo Then
ComboBox_UPC_C18.Value = ComboBox_UPC_C18_Value
MsgBox (ComboBox_UPC_C18_Value)
Exit Sub
End If
ComboBox_UPC_C18_Value = ComboBox_UPC_C18.Value
MsgBox (ComboBox_UPC_C18_Value)
End Sub
I wasn't able to test this but I think this is close to what you are looking for. Let me know if I am totally off base here:
Private Sub ComboBox_UPC_C18_Change()
Dim RngLocation As Range
Dim PrevLocation As String
Application.EnableEvents = False
PrevLocation = Range("Location_C18").Value
If PrevLocation = "" Then
Range("Location_C18").Value = ComboBox_UPC_C18.Value
Else
If MsgBox("Are you sure you want to change this?", vbYesNo) = vbYes Then
Range("Location_C18").Value = ComboBox_UPC_C18.Value
Else
ComboBox_UPC_C18.Value = PrevLocation
End If
End If
Application.EnableEvents = True
End Sub

How to detect if user select cancel InputBox VBA Excel

I have an input box asking user to enter a date. How do I let the program know to stop if the user click cancel or close the input dialog instead of press okay.
Something like
if str=vbCancel then exit sub
Currently, user can hit OK or Cancel but the program still runs
str = InputBox(Prompt:="Enter Date MM/DD/YYY", _
Title:="Date Confirmation", Default:=Date)
If the user clicks Cancel, a zero-length string is returned. You can't differentiate this from entering an empty string. You can however make your own custom InputBox class...
EDIT to properly differentiate between empty string and cancel, according to this answer.
Your example
Private Sub test()
Dim result As String
result = InputBox("Enter Date MM/DD/YYY", "Date Confirmation", Now)
If StrPtr(result) = 0 Then
MsgBox ("User canceled!")
ElseIf result = vbNullString Then
MsgBox ("User didn't enter anything!")
Else
MsgBox ("User entered " & result)
End If
End Sub
Would tell the user they canceled when they delete the default string, or they click cancel.
See http://msdn.microsoft.com/en-us/library/6z0ak68w(v=vs.90).aspx
Following example uses InputBox method to validate user entry to unhide sheets:
Important thing here is to use wrap InputBox variable inside StrPtr so it could be compared to '0' when user chose to click 'x' icon on the InputBox.
Sub unhidesheet()
Dim ws As Worksheet
Dim pw As String
pw = InputBox("Enter Password to Unhide Sheets:", "Unhide Data Sheets")
If StrPtr(pw) = 0 Then
Exit Sub
ElseIf pw = NullString Then
Exit Sub
ElseIf pw = 123456 Then
For Each ws In ThisWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next
End If
End Sub
The solution above does not work in all InputBox-Cancel cases. Most notably, it does not work if you have to InputBox a Range.
For example, try the following InputBox for defining a custom range ('sRange', type:=8, requires Set + Application.InputBox) and you will get an error upon pressing Cancel:
Sub Cancel_Handler_WRONG()
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
If StrPtr(sRange) = 0 Then 'I also tried with sRange.address and vbNullString
MsgBox ("Cancel pressed!")
Exit Sub
End If
MsgBox ("Your custom range is " & sRange.Address)
End Sub
The only thing that works, in this case, is an "On Error GoTo ErrorHandler" statement before the InputBox + ErrorHandler at the end:
Sub Cancel_Handler_OK()
On Error GoTo ErrorHandler
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
MsgBox ("Your custom range is " & sRange.Address)
Exit Sub
ErrorHandler:
MsgBox ("Cancel pressed")
End Sub
So, the question is how to detect either an error or StrPtr()=0 with an If statement?
If your input box is an array, it does not work. I have solved it by adding a check for if it is an array first.
Dim MyArrayCheck As String
Dim MyPlateMapArray as variant
MyPlateMapArray = Application.InputBox("Select ....", Type:=8)
MyArrayCheck = IsArray(MyPlateMapArray)
If MyArrayCheck = "False" Then
Exit Sub
End If
I have solved it with a False like below
MyLLOQ = Application.InputBox("Type the LLOQ number...", Title:="LLOQ to be inserted in colored cells.", Type:=1)
If MyLLOQ = False Then Exit Sub
If user click cancel the sub will exit.
Another suggestion.
Create a message box when inputbox return null value. Example:
Dim PrC as string = MsgBox( _
"No data provided, do you want to cancel?", vbYesNo+vbQuestion, "Cancel?")
Sub TestInputBox()
Dim text As String
text = InputBox("Type some text")
If text = "" Then
MsgBox "button cancel pressed or nothing typed"
Else
MsgBox text
End If
End Sub
Inputbox send a boolean False value when Cancel is pressed.
contenidoy = Application.InputBox("Cantidad = ", titulox, contenidox, , , , , Type:=1)
'ESC or CANCEL
If contenidoy = False Then
MsgBox "Cancelado"
Else
MsgBox "EdiciĆ³n aceptada"
'End If

Resources