MS Access Multi-control KeyPress CTRL+A Handler - ms-access

I have an Access database with 10+ text controls. I'd like to have some code to handle the CTRL + A KeyPress event. Normally, when pressing CTRL + A in Access, this selects all records. My end goal is to have CTRL + A only select that control's text (like pressing CTRL + A in your browser's URL bar, it only selects THAT text) so that I can delete only that control's text. I checked this article, as I wanted something that could handle any text box (handling each textbox's KeyPress = 60+ lines of code). Is there any way I could have, say, a for-next loop?
Function HandleKeyPress(frm As Form, KeyAscii As Integer, ByVal e As KeyPressEventArgs) 'should it be a function or a sub?
For Each ctl In Me.Controls
If KeyAscii = 1 Then 'I think this is CTRL + A?
e.Handled = True 'Stop this keypress from doing anything in access
focused_text_box.SelStart = 0
focused_text_box.SelLength = Len(focused_text_box.Text)
End If
Next
End Function
Along with this, how can I pass to this sub/function the text box's name?
Note: In case you haven't noticed yet, I'm still a noob with VBA/Access.

Your current approach will not work, since it contains multiple things that just don't work that way in VBA (as June7 noted), and since form keydown events take priority over textbox keydown events
You can use the following code instead (inspired by this answer on SU):
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyA And Shift = acCtrlMask Then 'Catch Ctrl+A
KeyCode = 0 'Suppress normal effect
On Error GoTo ExitSub 'ActiveControl causes a runtime error if none is active
If TypeOf Me.ActiveControl Is TextBox Then
With Me.ActiveControl
.SelStart = 0
.SelLength = Len(.Text)
End With
End If
End If
ExitSub:
End Sub
It's important to set the Form.KeyPreview property to True, either using VBA or just the property pane, to allow this function to take priority over the default behaviour.

Related

Unable to disable all fields of a ms-access userform on load

I have lots of controls on my userform and I want to disable all of them on load except for "login button" and "Shift Date" textbox, so i am using the code below:
Private Sub Form_Load()
Call GetValues
Me.WlcmLabel.Caption = "Hi " + GetUserName + " ! "
Dim ctrl As Control
For Each ctrl In Me.Controls
ctrl.Enabled = False
Next
Me.ShiftDate.Enabled = True
Me.LoginBtn.Enabled = True
Set ctrl = Nothing
End Sub
but this gives me an error on load saying "object does not support this property or method."
all the controls will get enabled as soon as the user clicks on login button.
What would be the mistake in my code ?
Please ask if any other information required.
Thank You !
Try locking the control instead. I have used the locked property below, but I use the tag property of each control to identify it as lockable. So the controls you don't want to lock will not get anything in the tag property, and therefore will not lock. For your application, you could flip the logic since you only want leave the two controls unlocked.
For Each ctlCurr In Me.Controls
If ctlCurr.Tag = "Lockable" Then
ctlCurr.Locked = True
End If
Next
You can't disable label control that's why that error is coming. You have to check the type of control.
For Each ctrl In Me.Controls
With ctrl
a = TypeName(ctrl)
Select Case .ControlType
Case acLabel
Case acEmptyCell
Case Else
ctrl.Enabled = False
End Select
End With
Next ctrl
Apply disable only when it's not label.

How to Absorb a Keypress?

On my form I have an edit control. I have set up a KeyDown event to detect when the user pushes enter, but I also want to detect shift+space so the user can clear the contents of the box.
The functionality works - I can detect the keypress. Problem is that the space does not get absorbed and so the space glyph is still typed in the control.
How can I absorb the keypress when I push shift+space?
Private Sub FindBox_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyEnter: SearchForIt
Case vbKeySpace:
If Shift = 1 Then
FindBox.Text = ""
'here absorb keypress instead of sending space to control
Exit Sub
End If
End Select
End Sub
You just need to set the value of KeyCode = 0. That will "swallow" the key and not have anything happen.
You also want to use the bit mask to look for the presence of the shift being pressed
Dim intShiftDown As Integer
intShiftDown = (Shift And acShiftMask) > 0
Case vbKeySpace:
If intShiftDown Then
FindBox.Text = ""
'here absorb keypress instead of sending space to control
KeyCode = 0
Exit Sub
Oh, I figured it out.
It was simple.
'here absorb keypress instead of sending space to control
KeyCode = 0

Alternative to SendKeys "{Esc}" for unbound text box Undo

I have an unbound textbox control. The user enters some valid text and leaves the control. The user then returns to the control and enters some invalid text. I want to show the user a message then rollback the value of the control to its previous state and keep the focus in that control.
I've tried the following approaches, none of which gets me exactly what I am looking for:
OPTION A: SendKeys
Private Sub MyTextBox_BeforeUpdate(Cancel As Integer)
Cancel = DataIsInvalid(Me.MyTextBox.Value)
If Cancel Then SendKeys "{Esc}"
End Sub
This does exactly what I want, but I really want to avoid using SendKeys. There are many problems that come with using SendKeys: Vista+ compatibility, keys being sent to a different application, etc.
OPTION B: Undo method of control
Private Sub MyTextBox_BeforeUpdate(Cancel As Integer)
Cancel = DataIsInvalid(Me.MyTextBox.Value)
If Cancel Then Me.MyTextBox.Undo
End Sub
This is simply broken for unbound controls (at least as of MS Access 2002/XP). This method does not restore the value of MyTextBox to the valid input. However, it does allow the user to change the focus to a new control while leaving the invalid input in place in Me.MyTextBox! Unbelievable!!!
OPTION C: Undo method of form
Private Sub MyTextBox_BeforeUpdate(Cancel As Integer)
Cancel = DataIsInvalid(Me.MyTextBox.Value)
If Cancel Then Me.Form.Undo
End Sub
The Undo here does absolutely nothing. But at least it doesn't break the BeforeUpdate Cancel=True code and allow the invalid data to stand.
OPTION D: Explicitly restore old value in BeforeUpdate event
Private mPrevMyTextBoxValue As Variant
Private Sub MyTextBox_AfterUpdate()
mPrevMyTextBoxValue = Me.MyTextBox.Value
End Sub
Private Sub MyTextBox_BeforeUpdate(Cancel As Integer)
Cancel = DataIsInvalid(Me.MyTextBox.Value)
If Cancel Then Me.MyTextBox.Value = mPrevMyTextBoxValue
'If Cancel Then Me.MyTextBox.Text = mPrevMyTextBoxValue
End Sub
Attempts to assign the previous value to either the .Value or .Text property of the textbox result in the same error message:
The macro or function set to the BeforeUpdate or ValidationRule property for this field is preventing {Program Name} from saving the data in the field.
OPTION E: Explicitly restore old value in AfterUpdate event
Private mPrevMyTextBoxValue As Variant
Private Sub MyTextBox_AfterUpdate()
If DataIsInvalid(Me.MyTextBox.Value) Then
Me.MyTextBox.Value = mPrevMyTextBoxValue
Me.MyTextBox.SetFocus
Else
mPrevMyTextBoxValue = Me.MyTextBox.Value
End If
End Sub
This is really close to the desired behavior. Unfortunately, it's impossible to keep the focus on the control because the AfterUpdate event runs before the Tab/Enter keypress or mouse-click events are processed. So even if we try to force the focus to the proper control (via the .SetFocus statement above), the program will immediately shift the focus to the control the user selected.
It seems to me that the "right" way to do this is to use the .Undo method of the control. That does not work for unbound controls, though. This is an inexplicable shortcoming, especially given the fact that an Escape key-press performs this functionality for an unbound field.
Is there a better way to do this or should I just stick to using SendKeys?
After getting to page 3 on google I decided to just muck around and see what sort of ordering happens when trying your Option E. Below is the best workaround method I was able to use to get focus to "Stay" on the textbox in question.
Private mPrevMyTextBoxValue As Variant
Private Sub Text0_AfterUpdate()
If Me.Text0.Value = 0 Then
Me.Text0.Value = mPrevMyTextBoxValue
Me.Text12.SetFocus
Me.Text0.SetFocus
Else
mPrevMyTextBoxValue = Me.Text0.Value
End If
End Sub
0 simulates that it failed the validation. It seems like if you set focus to something else before setting it back to the textbox you are working with it will stay there. I don't have an answer as to why unfortunately.
Edit: I have decided to try to program my theory as to how this works.
Private blnGoToNextControl as Boolean
Private Function SetFocus(ctrl As control)
blnGoToNextControl = True
If ctrl.HasFocus = True Then
'Do nothing
Else
ctrl.HasFocus = True
blnGoToNextControl = False
End If
End Function
This is my idea of how the SetFocus function works. So then after the AfterUpdate event runs it would check to see if the flag to go to next control is and see that it is set to false and not go to the next control.
Rough coding obviously but hopefully this gets my theory across?
If it is unbound, why not use the AfterUpdate event:
Private Sub MyTextBox_AfterUpdate()
If DataIsInvalid(Me!MyTextBox.Value) Then
Me!MyTextBox.Value = Null
Me!MyTextBox.SetFocus
End If
End Sub
or modify your other solution:
Private Sub MyTextBox_AfterUpdate()
Static mPrevMyTextBoxValue As Variant
If IsEmpty(mPrevMyTextBoxValue) Then
mPrevMyTextBoxValue = Null
End If
If DataIsInvalid(Me!MyTextBox.Value) Then
Me!MyTextBox.Value = mPrevMyTextBoxValue
Me!MyTextBox.SetFocus
Else
mPrevMyTextBoxValue = Me!MyTextBox.Value
End If
End Sub
Try moving the focus off the textbox, then back:
Me!MyTextBox.Value = mPrevMyTextBoxValue
Me!SomeOtherControl.SetFocus
Me!MyTextBox.SetFocus
That someothercontrol can be a tiny nearly hidden textbox.

Dirty event not firing on Access 2007 form

I have a bound pop up form with a Clear data button. It runs the Undo command.
The Form_Current event sets this button's enable property to False.
The Form_Dirty event sets this button's enable property to True.
The button's property is always set to False even after I enter data into the form. I think this is because my Form_Load event is populating two fields. One is passed from the main form as an OpenArgs, the other is the unique ID which is calculated based on the OpenArgs value.
Any suggestions as to how to get the Dirty event to activate under these circumstances? If not, then an alternative approach perhaps?
Thanks in advance.
Code below:
Private Sub cmdUndoChanges_Click()
CustID_temp = Me!CustID
FacNo_temp = Me!Unique_ID
DoCmd.RunCommand acCmdUndo
Me!CustID = CustID_temp
Me!Unique_ID = FacNo_temp
End Sub
Private Sub Form_Current()
Me!cmdUndoChanges.Enabled = False
End Sub
Private Sub Form_Dirty(Cancel As Integer)
Me!cmdUndoChanges.Enabled = True
End Sub
Private Sub Form_Load()
Dim test As Integer
Me!CustID = OpenArgs
test = DCount("Unique_ID", "tbl_Table2", "CustID = '" & Me!CustID & "'")
If IsNull(Me!UNIQUE_No) Then
test = test + 1
Me!Unique_ID = CustID & "-" & test
MsgBox "No Previous Data"
Else
' these will be turned back on when the user selects the
' modify data button or add new data button.
For Each ctl In Me.Controls
Select Case ctl.ControlType
Case acTextBox, acComboBox, acOptionGroup, acCheckBox
ctl.Locked = True
ctl.BackColor = 15066597
Box40.BackColor = 15066597
End Select
Next ctl
End If
MsgBox Me!Unique_ID
End Sub
Have you tried Form_BeforeInsert() instead of Form_Dirty()?
I found another case where the Form_Dirty event never fires, the hard way. I thought I'd add it here since this is the top search result for the "not firing" question.
If your Form_Load function does anything to change the value of an existing record, the form will be set to dirty immediately, apparently before the logic that fires the event begins to run. Because of that there will never be an event if other data on the form is changed.
We had a "smart" Save button that was disabled until Form_Dirty fired. After I added a fixup to Form_Load for old records with a junk field, editing those records no longer ever enabled the Save button.

Do action if user starts to delete data from textbox

I have an access form with a text-box that user can update using a list-box or by editing it directly, I need to make an action if the user starts to delete from this text-box, if he starts to add data no problem only if he starts to delete from it, something like :
Private Sub textbox_AfterUpdate()
If Me.[textbox].SelStart = Len(Me.[textbox].Text) - 1 Then
' do something
else
' do something else
End If
End Sub
You might want to use the KeyDown event instead of AfterUpdate
This captures the Backspace and the Del button.
Private Sub Text0_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = 8 Or KeyCode = 46 Then
MsgBox "Text was deleted"
End If
End Sub
There can be other scenarios where the text is deleted for example Ctrl + X So you can trap all that.
You might like to consider the change event, the text property is the current unsaved content of the control that has focus and the value property is the saved content of the control with focus.
The advantage of Change is that the user cannot simply insert letters into the existing string, for example, the user cannot change 20 meters to 200 meters.
Private Sub AText_Change()
''If the current content is the same as the
''previous content with something added
If Me.AText.Text Like Me.AText.Value & "*" Then
''Ok
Else
''Problem
MsgBox "Not allowed"
Me.AText = Me.AText.Value
End If
End Sub
You could also allow the saved content to be a substring of the current content.