Access VBA - prevent closing form - ms-access

I have a code in Before_Update event, for saving changes. For this I use Msgbox with YesNoCancel prompt, but I cannot prevent closing form when I hit Cancel button. Here is a short sample of my code:
Option Compare Database
Public SomeVariable As Integer
Private Sub Form_BeforeUpdate(Cancel As Integer)
If MsgBox("There has been done some changes. You wish to save these changes ?", vbQuestion + vbYesNoCancel, "Save changes") = vbYes Then
'do nothing and Access saves automatically
ElseIf vbNo Then
DoCmd.RunCommand acCmdUndo
ElseIf vbCancel Then
SomeVariable = 1
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
If SomeVariable = 1 Then
SomeVariable=0
Cancel = True
End If
End Sub
Any way to fix this ?

You must save the return value from MsgBox, then proceeed accordingly:
Dim vbAnswer
vbAnswer= MsgBox("There has been done some changes. You wish to save these changes ?", vbQuestion + vbYesNoCancel, "Save changes")
if vbAnswer = vbYes Then
'do nothing and Access saves automatically
ElseIf vbAnswer= vbNo Then
....
ElseIf vbAnswer= vbCancel Then

Related

Access-VBA check if the cursor in a Textbox is in the first or last line

The Goal: I've got an Access database with a continuous form and I want to add the functionality that you can go to the next or previous record by pressing the up- or down-arrow.
The Problem: I've got a multiline TextBox named txtProjekt and I want the database to check if the TextBox is filled with multi-lined text and only jump to the next record if the cursor is in the last line of the TextBox. Likewise I want it to only jump to the previous record if the cursor is in the first line of the TextBox.
I can only check the current cursor position with SelStart, but I can't find out in which line the cursor is.
Do you have any ideas?
Current code:
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
On Error GoTo err_Form_KeyDown
If Me.ActiveControl.Name = "txtProjekt" Then
If Not (Me.txtProjekt.SelStart = 0 And Me.txtProjekt.SelLength = Len(Me.txtProjekt.Text)) Then
GoTo exit_Form_KeyDown
End If
End If
If KeyCode = vbKeyUp Then
DoCmd.GoToRecord acActiveDataObject, Record:=acPrevious
KeyCode = 0
ElseIf KeyCode = vbKeyDown Then
DoCmd.GoToRecord acActiveDataObject, Record:=acNext
KeyCode = 0
End If
exit_Form_KeyDown:
Exit Sub
err_Form_KeyDown:
MsgBox Err.description
Resume exit_Form_KeyDown
End Sub
edit:
The Result (thanks to #Newd):
(be sure to active KeyPreview in your Form, otherwise it won't do anything)
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
On Error GoTo err_Form_KeyUp
If Shift = False Then
keyAction KeyCode, True
End If
exit_Form_KeyUp:
Exit Sub
err_Form_KeyUp:
MsgBox Err.description
Resume exit_Form_KeyUp
End Sub
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
On Error GoTo err_Form_KeyDown
Dim curPos As Integer
If Shift = False Then
keyAction KeyCode, False
End If
exit_Form_KeyDown:
Exit Sub
err_Form_KeyDown:
MsgBox Err.description
Resume exit_Form_KeyDown
End Sub
Private Sub keyAction(KeyCode As Integer, KeyUp As Boolean)
On Error GoTo err_keyAction
Static curPos As Long
If KeyUp = False Then
If Me.ActiveControl.Name = "txtProjekt" Then
If Not (Me.txtProjekt.SelStart = 0 And Me.txtProjekt.SelLength = Len(Me.txtProjekt.Text)) Then
curPos = Me.txtProjekt.SelStart
GoTo exit_keyAction
End If
End If
Else
If Me.ActiveControl.Name = "txtProjekt" Then
If curPos >= 0 Then
If Me.txtProjekt.SelStart <> curPos Then
GoTo exit_keyAction
End If
curPos = -1
Else
GoTo exit_keyAction
End If
End If
End If
If KeyCode = vbKeyUp Then
DoCmd.GoToRecord acActiveDataObject, Record:=acPrevious
KeyCode = 0
ElseIf KeyCode = vbKeyDown Then
DoCmd.GoToRecord acActiveDataObject, Record:=acNext
KeyCode = 0
End If
exit_keyAction:
Exit Sub
err_keyAction:
MsgBox Err.description
Resume exit_keyAction
End Sub
(I know, all those GoTo Exit_keyAction is bad style, so don't copy too much from me)
I don't currently have the time to write this code out in full to incorporate your code as well. However I think if you were able to get to the point you are at right now you should be able to utilize it.
Basically it is just a way to tell if the user has hit the end or beginning of the Multi-line textbox.
Public intOnDown As Integer
Public intOnUp As Integer
'When the user presses key down
Private Sub txtProjekt_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyUp Or KeyCode = vbKeyDown Then
'Save the cursor position
intOnDown = txtProjekt.SelStart
End If
End Sub
'When the user lets go of the key
Private Sub txtProjekt_KeyUp(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyUp Or KeyCode = vbKeyDown Then
If intOnDown - txtProjekt.SelStart = 0 Then 'If the SelStart is the same
Debug.Print "Pointer hasn't moved so must be at the end or beginning"
End If
End If
End Sub
With the above code you listen for when the user has pressed the up or down key on Keydown then you listen again on KeyUp (When they let go of the key). Then you check to see if the SelStart has changed. If it hasn't then it must mean they are at the beginning or the end of the field and you can perform the record switching.
Note: Adjust accordingly if you have memo fields that are going to be over the max integer size by changing to a long and you probably want to have error handling for it regardless.

How can I remove the pesky "The runCommand action was canceled" dialog box after a "cancel = true" statement

On the Form_beforeupdate() event of my form "Alias" I have this...
If IsNull(Me.txtFName) And IsNull(Me.txtLName) Then
MsgBox "You must enter a contact!", vbokayonly, "Contact"
Cancel = True
End If
Anytime this cancels a runCommand code such as...
DoCmd.RunCommand acCmdSaveRecord
a dialog appears telling me that it was canceled. Is there a way to suppress those dialogs?
You can add an error handler to trap and ignore error 2501, which is triggered when the form's Before Update event cancels DoCmd.RunCommand acCmdSaveRecord
The following example is from my form which has a command button to save the current record. It suppresses that "RunCommand action was canceled" message as I think you wish.
Since your form's code apparently calls DoCmd.RunCommand acCmdSaveRecord from multiple locations, replace each of those calls with SaveRecord as I did in cmdSave_Click().
Option Compare Database
Option Explicit ' <-- NEVER troubleshoot VBA code without this!!!
Private Sub cmdSave_Click()
'DoCmd.RunCommand acCmdSaveRecord
SaveRecord
End Sub
Private Sub SaveRecord()
Dim strMsg As String
On Error GoTo ErrorHandler
DoCmd.RunCommand acCmdSaveRecord
ExitHere:
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 2501 ' The RunCommand action was canceled.
' do nothing --> just ignore the error
Case Else
' notify user about any other error
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ") in procedure SaveRecord"
MsgBox strMsg
End Select
Resume ExitHere
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
If IsNull(Me.txtBlock_start.Value) Then
MsgBox "You must enter a start time!", vbOKOnly, "Start Time"
Cancel = True
End If
End Sub
I ended up doing this on a 'Save and Open the Receipts form' button.
Private Sub btnSaveOpenReceipts_Click()
'''''SaveRecord'''''
If (Me.Dirty) Then
SaveRecord
End If
'''''OpenReciepts'''''
If (Me.Dirty) Then 'unsure it saved
Exit Sub
Else
'blah blah blah
End If
End Sub

ms access form closing ask save yesnocancel

I have put the VBA in Unload Form Event in ms access 2010
Private Sub Form_Unload(Cancel As Integer)
Dim strMsg As String
Dim iResponse As Integer
' Specify the message to display.
strMsg = "Do you wish to save the changes?" & Chr(10)
strMsg = strMsg & "Click Yes to Save or No to Discard changes."
' Display the message box.
iResponse = MsgBox(strMsg, vbQuestion + vbYesNoCancel, "Save Record?")
' Check the user's response.
If iResponse = vbYes Then
' Undo the change.
DoCmd.RunCommand acCmdSave
End If
If iResponse = vbNo Then
' Undo the change.
DoCmd.RunCommand acCmdUndo
End If
If iResponse = vbCancel Then
' Undo the change
Cancel = True
End If
End Sub
If data is changed then the above code is working fine, then yes to save & close, No to undo & close and cancel to cancel event and remain on the form
but when the data is unchanged then Yes button is working fine, but NO button do not close the form
Where I m mistaking ?
Your question is too vague because you simply state "NO button do not close the form."
You can do:
DoCmd.Close
See here:
Private Sub cmdCloseForm_Click()
On Error GoTo Err_cmdCloseForm_Click
DoCmd.RunCommand acCmdUndo 'OR Me.Undo - test which works best for your situation
DoCmd.Close
Exit_cmdCloseForm_Click:
Exit Sub
Err_cmdCloseForm_Click:
MsgBox Err.Description
Resume Exit_cmdCloseForm_Click
End Sub
On Me.Undo from Allen Browne:
Me.Undo cancels the edits in a specific form, so that it is no longer dirty.
Once the form is no longer dirty, no further undo is possible, because it
has reached the desired state. However, Me. represents the form that is in focus, so your form must have focus to perform the Me.Undo command.

Why is my .setfocus ignored?

I have an Access form with a textbox that is meant to allow for repeatedly typing a number, hitting enter, and letting a script do stuff. For speed, the field should keep the focus after DoStuff() is done.
However, while I'm sure that DoStuff() is run, the focus always goes to the next field in the tab order. It's like Me.MyFld.SetFocus is being ignored.
How do I keep the focus on this field after DoStuff() is done?
Private Sub MyFld_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then
DoStuff
Me.MyFld.SetFocus
End If
End Sub
If you look at the order of events for a keypress that would change focus, you can see that it always follows this pattern:
KeyDown → BeforeUpdate → AfterUpdate → Exit → LostFocus
You can re-set the focus anywhere in there and it will still keep following the pattern. So we need to tell it to stop following the pattern. Replace your Me.MyFld.SetFocus with DoCmd.CancelEvent and it should fix your problem. Basically, this just kicks you out of the above pattern, so the Exit and LostFocus events never fire...
A workaround is moving the focus to another control and then back to the first control. Like this:
Private Sub MyFld_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then
DoStuff
Me.anotherControl.SetFocus
Me.MyFld.SetFocus
End If
End Sub
click on access options
select Advanced
select Don't move from Move after enter
click ok
It will work 100%
Try removing the whole line for variable_name.SetFocus and simply add:
Cancel = True
Private Sub MyFld_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then
DoStuff
Cancel = True
End If
End Sub
Another solution to the problem that I use in Excel.
Let there exist UserForm1 with the TextBox1 and CommandButton1 controls.
Code in the form module:
Option Explicit
Private Sub CommandButton1_Click()
Unload Me
End Sub
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = vbKeyReturn Then
'Call DoStuff
Application.OnTime Now, "'Control_SetFocus """ & Me.Name & """, """ & Me.ActiveControl.Name & """ '"
' The concatenation returns a string: 'Control_SetFocus "UserForm1", "TextBox1"'
End If
End Sub
And code in the standard module:
Option Explicit
Sub Control_SetFocus(FormName As String, ControlName As String)
Dim oUserForm As Object
Set oUserForm = GetFormByName(FormName)
If Not oUserForm Is Nothing Then
oUserForm.Controls(ControlName).SetFocus
End If
End Sub
Function GetFormByName(FormName As String) As Object
Dim oUserForm As Object
On Error GoTo ErrHandle
For Each oUserForm In VBA.UserForms
If StrComp(oUserForm.Name, FormName, vbTextCompare) = 0 Then
Exit For
End If
Next oUserForm
If oUserForm Is Nothing Then
Set oUserForm = UserForms.Add(FormName)
End If
Set GetFormByName = oUserForm
Exit Function
ErrHandle:
Select Case Err.Number
Case 424:
MsgBox "Userform " & FormName & " not exists.", vbExclamation, "Get userform by name"
Case Else:
MsgBox Err.Number & ": " & Err.Description, vbCritical, "Get userform by name"
End Select
End Function
Artik
An easy solution that works in Excel is to set the KeyCode to 0. If DoStuff steals the focus then you should also set the focus back:
Private Sub MyFld_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then
DoStuff
KeyCode = 0
Me.MyFld.SetFocus
End If
End Sub

Prompt before close

Before the user closes the form I want to prompt with a confirmation box.
I am not sure how to do this.
I have tried the code below and it prompts the user but upon clicking no it closes the form anyway:
Private Sub Form_Close()
If MsgBox("Test", vbYesNo + vbExclamation, "Confirm close") = vbYes Then
Else
Cancel = True
End If
End Sub
You can't cancel the close event but you can cancel the unload event
Private Sub Form_Unload(Cancel As Integer)
If MsgBox("Test", vbYesNo + vbExclamation, "Confirm close") <> vbYes Then
Cancel = True
End If
End Sub