How do I run a macro on change to a field, but not on original entry of that field? - vba

I created a Projects database which includes a form with fields for staff to complete on startup of a project.
The first field, 'ClientCode' is a compulsory dropdown list (Combobox) of Clients.
To avoid accidental changes to this field, I added 'On Change' code to display a warning message:
Private Sub ComboClientCode_Change()
If MsgBox("Are you sure you want to change the client?", vbQuestion + vbYesNo) = vbNo Then
DoCmd.RunCommand acCmdUndo
Else
Exit Sub
End If
End Sub
It works, however I don't want it to run when someone starts a new record i.e. selects the client for the first time.
How do I make this message only show if it is a change to the original entry?
I tried moving it to 'AfterUpdate' but it does the same thing.

Right, I haven't tested any of the code below so let me know if it works for you. I propose 2 different solutions, and depending on if the logic works, the solution will work.
Solution 1:
Using the change event, you check the combobox value, and if it is blank then run the code. My concern with this is that when the event handler fires there will only be a value in there because the user would have changed the value to call the event handler. Nonetheless, the code would look like something below.
Private Sub ComboClientCode_Change()
If Me.ComboClientCode.Value <> "" Then
If MsgBox("Are you sure you want to change the client?", vbQuestion + vbYesNo) = vbNo Then
DoCmd.RunCommand acCmdUndo
Else
Exit Sub
End If
End If
End Sub
Solution 2:
With this solution the logic seems a bit more sound than the above method. What will happen is you will set the default value of the combobox using the UserForm_Initialize() event handler. Then, when your user selects from the dropdown list it will set the value to that variable, and will prevent the unnecessary pop up. See below code. Your userform module should look like the below.
Option Explicit
Dim sClientCode As String
Private Sub UserForm_Initialize()
sClientCode = Me.ComboClientCode.Value
End Sub
Private Sub ComboClientCode_Change()
If sClientCode <> "" Then
If MsgBox("Are you sure you want to change the client?", vbQuestion + vbYesNo) = vbNo Then
'set the value now
sClientCode = Me.ComboClientCode.Value
DoCmd.RunCommand acCmdUndo
Else
Exit Sub
End If
End If
End Sub

You could change one of the "irrelevant" properties of the combobox the first time it gets changed.
Private Sub ComboClientCode_Change()
If ComboClientCode.ColumnHeads = False Then
ComboClientCode.ColumnHeads = True
Else
If MsgBox("Are you sure you want to change the client?", vbQuestion + vbYesNo) = vbNo Then
'DoCmd.RunCommand acCmdUndo
Debug.Print "DoCmd.RunCommand acCmdUndo"
Else
Exit Sub
End If
End If
End Sub
Should work for this type:
Listed properties of above selected type:
You can run this to make the existing one change if it has a value:
Sub Switch()
If ComboClientCode.Value <> "" Then
ComboClientCode.ColumnHeads = True
Else
ComboClientCode.ColumnHeads = False
End If
End Sub

Related

How do I undo a change to a combo box in Access?

I'm trying to prevent users from accidentally changing a combo box selection once they've already made the selection, by having a yes/no message box appear during the On Change event of the combo box.
The Undo isn't working. The new value is still in the field after they click No.
The idea is if they select No the previous value will be input rather than the new one.
I tried the Before Update and After Update as well, but it doesn't seem to make any difference.
Private Sub CboClient_Change()
If MsgBox("Do you want to change the client?", vbYesNo) = vbNo Then
Me!CboClient.Undo
End If
End Sub
Use combobox OldValue property. This works for me:
Private Sub cboClient_BeforeUpdate(Cancel As Integer)
With Me
If Not IsNull(.cboClient.OldValue) And .cboClient.OldValue <> .cboClient Then
If MsgBox("Do you want to change the client?", vbYesNo) = vbNo Then
Cancel = True
.cboClient.Undo
End If
End If
End With
End Sub

Can I add a UI action confirmation?

I have a form that displays a record (about 40 fields). I have a button to duplicate the record in instances where a slight change is needed (i.e. A541AB becomes A541AC). I've seen a couple of instances of solutions on the interwebs but I couldn't find one that works for this UI action. Is it possible to create a confirmation box asking if they're sure they want to duplicate the record? Currently, the button is designed using a macro since I'm not very good with Access VBA.
You need to do this in VBA by setting a flag to handle the auto-update. Upon clicking the button ask the user and save if the answer is Yes.
'Set a flag for manual update
Private mIsUserUpdate As Boolean 'Flag
'Cancel auto-update
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Not mIsUserUpdate Then Cancel = True
End Sub
'Save Button - Change 'YourButtonName'
Private Sub YourButtonName_Click()
If MsgBox("Are you sure you want to duplicate the record?", vbYesNo + vbQuestion, "Confirm") = vbYes Then
mIsUserUpdate = True 'flag ON
DoCmd.RunCommand acCmdSaveRecord
End If
mIsUserUpdate = False 'flag OFF again
End Sub

Creating a msg on close when sheets are unprotected in Excel

Hi I'm trying to make it so that excel will look if two specific sheets are protected on closure and then if they are not I want a message box to come up warning of this. Currently i've got this far with VBA.
Sub Worksheet_BeforeClose(Cancel As Boolean)
If Sheets("Dashboard Page").ProtectContents = True And Sheets("Tracker Sheet").ProtectContents = True Then
MsgBox "Protected"
ElseIf
MsgBox("Workbook is not protected please protect before closing", _
vbQuestion + vbOKOnly) = vbOKOnly Then
Cancel = True
End If
End If
End Sub
if anyone could help out that would be great.
Thanks
Edit: I'm now having issues with changing this to just an OK button that cancels the close. changes are above. It will just close if the OK button is clicked
The problem is you can not open a sub inside another one, but you can call it.
Sub ProtectMsg_BeforeClose()
If Sheets("Dashboard Page").ProtectContents = True And Sheets("Tracker Sheet").ProtectContents = True Then
MsgBox "Protected"
Else
Workbook_BeforeClose
End If
End Sub
Sub Workbook_BeforeClose()
If MsgBox("Workbook is not protected please protect before closing", _
vbQuestion + vbYesNo) = vbNo Then
Cancel = True
End If
End Sub
Try if it helps you.

Excel VBA ComboBox1_DropButtonClick Event

I got macro below which fires twice (showing same MessageBox twice). First when ComboBox1 opens and second when ComboBox1 closes.
Private Sub ComboBox1_DropButtonClick()
If Me.ComboBox2.Text = "" Then
MsgBox "Fill text box"
Else
'Do stuff
End If
End Sub
Is there any way to make it show MessageBox once. I want user to select the value in ComboBox1 first before clicking on ComboBox2 DropButton.
Here is a very unelegant work-around using a "count" variable that prompts the MsgBox only the first and not the second time.
Dim count As Integer
Private Sub ComboBox1_DropButtonClick()
count = count + 1
If Me.ComboBox2.Text = "" Then
If count = 1 Then
MsgBox "Fill text box"
Else
count = 0
End If
Else
'Do stuff
End If
End Sub
However, I highly suggest to use the ComboBox1_Change() event if it's not necessary to use the drop button one.
P.S.: the declaration of the "count" variable needs to stay out of the method. This is due to the fact that:
if it stays inside, it's a local variable of the method and so loses its modifications every time the method is ended;
if it stays outside, it will keep the modifications even once the method has ended its run.
I would do it using the combobox_enter event, but this only checks when the focus is switched
Private Sub ComboBox1_Change()
If ComboBox1.Text = "" Then
ComboBox2.ShowDropButtonWhen = fmShowDropButtonWhenNever
Else
ComboBox2.ShowDropButtonWhen = fmShowDropButtonWhenAlways
End If
End Sub
Private Sub ComboBox2_Enter()
If ComboBox1.Text = "" Then
MsgBox "Must first set value to combobox1"
ComboBox1.SetFocus
End If
End Sub
Private Sub UserForm_Initialize()
ComboBox1.AddItem "None", 0
ComboBox1.AddItem "Select Me", 1
ComboBox2.AddItem "None", 0
ComboBox2.AddItem "Select Me", 1
ComboBox2.ShowDropButtonWhen = fmShowDropButtonWhenNever
End Sub
My code does some extra things that I just think look pretty, you really only need the _Enter function

How to put focus to textbox as needed

I have a textbox on a userform. If the user fails to enter anything in this textbox, I need to trap that to force an entry. I can do this easily enough, but after notifying the user tht they need to make an entry, I want the focus to return to the textbox. Right now, it doesn't do that. Here is my code:
Private Sub txtAnswer_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 13:
If Me.txtAnswer.Value = "" Then
temp = MsgBox("You need to enter an answer!", vbCritical + vbOKOnly, "No Answer Found!")
Me.txtAnswer.SetFocus
Else
recordAnswer
End If
End Select
End Sub
This code works fine in that the message box pops up if the textbox is left blank. After clearing the message box, if I hit enter immediately again, the message box reappears, suggesting that the focus is on the textbox. However, if I try to enter a character (like the number '1' for example) nothing appears in the textbox.
Can anybody suggest how I can get the focus back on this textbox in a way that will allow the user to enter data? Thank you!
Why are you not using an 'ok' button to complete the action?
You should not bother users with messages while they are typing in a form. Do it at the end.
Private Sub OK_Click()
'// Validate form
If txtAnswer.Text = vbNullString Then
MsgBox "You need to enter an answer!", vbExclamation, "No Answer Found!"
txtAnswer.SetFocus
Exit Sub
End If
'// You have reached here so form is correct carry on
recordAnswer
End Sub
If you really want to use the behaviour you asked for then try this:
Private Sub txtAnswer_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 13:
If Me.txtAnswer.Value = "" Then
temp = MsgBox("You need to enter an answer!", vbCritical + vbOKOnly, "No Answer Found!")
KeyCode = 0
Else
recordAnswer
End If
End Select
End Sub
The problem is that in your code you are setting focus but the enter key is firing afterwards. You don't need to set focus because the textbox already has the focus you just need to cancel the enter key.
The other answers seem really complicated. I had a similar problem and really wanted a text warning. It seemed easier for me to just make an invisible label on the form that would show up if the input was incorrect. I also made the background of the label red so that the user would notice something was wrong. Doing it this way kept the cursor visible and right where they left off.
Public Function amount(ByRef cont As MSForms.TextBox) As Integer
'makes sure that a number is used
'could change to account for decimals if necessary
Dim i As Long
On Error Resume Next
i = 0
If (cont.Value = "") Then Exit Function
Do While i < 1000000
If (cont.Value = i) Then
UserForm1.Label257.Visible = False
Exit Function
End If
i = i + 1
Loop
UserForm1.Label257.Visible = True
amount = 1
End Function
Public Sub qty_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If amount(UserForm1.qty) = 1 Then
Cancel = True
End If
End Sub
I hope this helps other who run into this problem later on.
Looking at the above code, I assume the i counter is to keep it going? Sorry a bit rusty, been a few years since I've done code.
At any rate, if thats the case you could always run it while i=0, do (or while true).
Sorry, first time posting here, hope that made sense.