I have a data entry form where two of the fields are contained in a subform within the main form. We are using barcode scanners to enter data. These barcodes essentially press enter after every scan, however sometimes our barcodes are damaged and, when scanned, can sometimes add random special characters. When ever someone scans a barcode in the "Part Number" field that contains any of the following characters (+, #, %, =) i have a msgbox that pops up alerting the person scanning that the barcode didn't read correctly. After the message pops up I want to refocus on the "Part Number" field so that they can rescan the barcode or just type the data manually (if the barcode keeps being buggy) rather than having to click back in to that field, deleting the wrong data, then re entering the data. My code is below:
Private Sub Part_Number_LostFocus()
Dim RegEx As Object, MyString As String, Answer As Integer
Set RegEx = CreateObject("VBScript.RegExp")
MyString = [Forms]![frmInventoryCountEntry]![tblInventoryCount subform].Form![Part Number]
With RegEx
.Pattern = "[+#%=]+"
End With
If RegEx.Test(MyString) = True Then
MsgBox "Part Number Contains Invalid Character", vbOKOnly
DoCmd.GoToControl "tblInventoryCount subform"
DoCmd.GoToControl "Part Number"
I've tried set focus as well and no matter what the cursor always goes to the next field rather than refocusing on the "Part Number" field. I'm sure the solution is simple but I've tried a bunch of different things and I'm starting to get frustrated :( can anyone help me out? Btw, I'm using access 2003
Have you tried .SetFocus?
You might also consider using a Before Update event and then cancelling if the string contains those symbols. That way the focus never leaves the Part Number control.
Related
I have a Database in Access 2010 where the 1st field is a unique membership number. The field is set Indexed, no duplicates. If a duplicate is entered on the input form no error message is displayed and nothing else works until a unique number is entered. I need the code that would trap the error on the number field losing focus so that a message box would tell the user the problem and then set focus back to the number field or let the user cancel all input.
This is what I have and it causes Datatype errors
Private Sub Grumpy_No_BeforeUpdate(Cancel As Integer)
If DLookup(Str("[Grumpy_No]"), "Grumpy", Str("[Grumpy_No]") = Me!Str(Grumpy_No)) Then
MsgBox "Number has already been entered in the database."
Cancel = True
Me!Grumpy_No.Undo
End If
End Sub
Any clues as to where I am going wrong would be very much appreciated
Looks to me like you're heading in the right direction but you need to fix your DLookup expression. Its third argument must be a single string. I don't see why Str() is useful --- just build a string. Actually I would use DCount instead of DLookup, but then the same issues still apply.
Private Sub Grumpy_No_BeforeUpdate(Cancel As Integer)
If DCount("[Grumpy_No]", "Grumpy", "[Grumpy_No] = " & Me!Grumpy_No.Value) > 0 Then
MsgBox "Number has already been entered in the database."
Cancel = True
'Me!Grumpy_No.Undo '<- consider allowing the user to see the value which failed
End If
End Sub
Note, if you can make Grumpy_No an autonumber primary key, Access will supply unique values automagically, so you wouldn't need your own code to check those values.
I'm seeking advice for sorting an Access (2013) form's data source by accepting a single letter typed by the user. This question is more about a design strategy more than actual code, although code samples may be helpful as well.
The system I developed for a client has a form with a dataset that is sorted by a set of parameters I defined. All works and I have provided some real-time resorting methods for the users which can dynamically re-sort the bound dataset as needed. Again, all is working fine.
However, the system they used prior to this (a green screen terminal application believe it or not) had one feature they still miss very much and which should be easy to implement. That feature is to see the data on the screen of customers, for example, (which is a very long list) and to be able to either (1) type the first letter of the last name to automatically "scroll down" to that part of the list or (2) to filter the dataset for that first letter ALL BY TYPING JUST THAT LETTER. I proposed creating an unbound field they could mouse to, type a letter and hit enter but the feedback was that it takes time to mouse to, click, type and press enter. I proposed making buttons of each letter they could click to accomplish the same goal but again the same feedback.
This feature does make sense. If you have a list of 8,000 customers and you want to get quickly to the people with a last name starting with the letter "R" for instance, mousing to a scroll bar and dragging can become tedious for users doing this all day long. Instead, it would be a good idea if they could simply press the R key and go straight there.
I suspect the answer is simple but I just haven't found it. Is it setting a keydown event somewhere?
Set the form's KeyPreview property to True to give it a first shot at any keystrokes, then add a KeyDown event handler to the form like this (untested):
Private Sub Form_KeyDown(ByVal KeyCode As Integer, ByVal Shift As Integer)
Dim NoTextBoxFocused As Boolean
' Make sure we're not stealing text from focused control
NoTextBoxFocused = TypeName(ActiveControl) <> "TextBox" And _
TypeName(ActiveControl) <> "ComboBox"
If KeyCode >= vbKeyA And KeyCode <= vbKeyZ And NoTextBoxFocused Then
' PSEUDOCODE: Sort here, presumably case-insensitive;
' otherwise, check for capitals with this:
' If (Shift And acShiftMask) <> 0 Then
KeyCode = 0 ' Turns off further handling
End If
' Otherwise, fall through without doing anything else
End Sub
You might also want to expand this to a full incremental search, complete with a label or textbox shown only when searching which filters progressively as the users type in the first few letters of whatever they want. If you show a textbox, make sure it's easy to start a new incremental search (with Esc or perhaps just a timeout). That should help wean them off missing the old program.
Simply use any control (combobox, listbox, textbox, button) and in an AfterUpdate Or OnClick Event run an ApplyFilter embedded macro or vba RunCommand using an SQL LIKE clause:
ComboBox: Letter Filter
Row Source: "A";"B";"C"; ... "Z"
Row Source Type: Value List
ApplyFilter
Filter Name: <blank>
Where Condition: ="[LastName] LIKE '" & [Forms]![Customers]![LetterFilter] & "*'"
Control Name: <blank>
Alternatively, with same controls and trigger events, update the form's recordsource:
Recordsource: SELECT * FROM [Customers]
WHERE [LastName] LIKE [Forms]![Customers]![LetterFilter] & '*'
OR synonymous query using Left()
Recordsource: SELECT * FROM [Customers]
WHERE Left([LastName], 1) = [Forms]![Customers]![LetterFilter]
OR SQL query in VBA:
Forms!Customers.Form.RecordSource = "SELECT * FROM [Customers]
WHERE [LastName] LIKE '" & [Forms]![Customers]![LetterFilter] & "*'"
Remember setting RecordSource is not in VBA but the query window
I am creating a small Access DB for our Data Entry guys. Our main DB is mysql but due to ease of use we are creating an Access DB to make it easier for them to enter the Data. I have done most of it but am stuck with this problem (which I know how to solve in mysql+php) Please pardon my ignorance, but I have just started using MS Access.
I have two tables - ClientPhones and sales. The ClientPhones table has phone, clientid fields. sales table has salesid, clientid, date, etc fields.
I also have a Form which has all relevant fields for the sales table. I want to add a new field, phone_no in that form. When a user inputs the number and on focus lose event, I was access to run a query on the clients table to see if the phone number exists in any of the 3 phone number fields. If it finds a client with that phone number, the client ID should be populated, else a new form to input the client details should be shown.
Is this possible with MS access or am I doing this incorrectly?
Use the text box's After Update event to retrieve the clientid which matches the phone number the user entered.
If a clientid is found, store it in the text box which is bound to clientid.
If no match is found, ask whether the user wants to add a new client, and open that form if they respond yes.
This code outline assumes txtSearchPhone is the name of the text box where the user enters the target phone number, and txtClientId is the name of the text box where you want to store clientid.
Private Sub txtSearchPhone_AfterUpdate()
Dim varClientId As Variant
Dim strCriteria As String
strCriteria = "[phone]='" & Me.txtSearchPhone.Value & "'"
Debug.Print strCriteria '<-- inspect this in Immediate window; Ctrl+g will take you there
varClientId = DLookup("clientid", "ClientPhones", strCriteria)
If IsNull(varClientId) Then
If MsgBox("Add new user?", vbYesNo) = vbYes Then
'DoCmd.OpenForm ... (see Access help topic)
End If
Else
Me.txtClientId.Value = varClientId
End If
End Sub
Make sure the text in txtSearchPhone does not include a single quote character (') because the DLookup will break if it does. You can use the text box's Validation Rule and/or Before Update event to make sure a single quote is not present.
I have an Access 2002 database/application where my clients can enter multiple information about their own clients, including a code which follow some rules.
However, when they view these information after they have been entered, I need to hide every characters in this code except for the 4 last characters. However, the agent needs to be able to edit this code if it needs to be modified.
So basically, I have 3 phases possible:
First time information are filled, empty data. The field must show the characters entered.
At a later date, the code must be hidden in some way to show only the last 4 characters. It can be with * or simply the last 4 characters, but the user must not be able to see what is before these.
The agent edit the code, the code must then be properly modified in the database. The characters must be shown.
I tried to show only the 4 last characters, however my database gets modified... So the code gets cut in the database.
I wrote the following function to obscure sensitive data. Its primary use is to discourage shoulder surfing. I'm not sure if it will meet your particular needs, but it is simple, straightforward and may help others who stumble upon this question.
'Use to hide data in sensitive fields (e.g., BirthDate, PhoneNum, SSN)
'Usage: Ctl OnEnter property: =ObscureInfo(False, Form.ActiveControl)
' Ctl OnExit property: =ObscureInfo(True, Form.ActiveControl)
' Form Open property: =ObscureInfo(True, [BirthDate], [HomePhone], [SSN])
Function ObscureInfo(HideIt As Boolean, ParamArray Ctls() As Variant)
Dim Ctl As Variant
For Each Ctl In Ctls
If HideIt Then
If IsNull(Ctl.Value) Then
Ctl.BackColor = vbWhite
Else
Ctl.BackColor = Ctl.ForeColor
End If
Else
Ctl.BackColor = vbWhite
End If
Next Ctl
End Function
Wow - I'm shocked that this hasn't been answered sufficiently. The best answer is to use an unbound text box in your form instead of a bound one. First you'll need to make your unbound text box populate the actual field. You'll do that in the AfterUpdate event.
Private Sub UnboundTextBox_AfterUpdate()
[MyField] = Me.UnboundTextBox
End Sub
Then you'll need to set an OnCurrent event to populate your unbound text box with the protected view whenever the agents view the record:
Private Sub Form_Current()
Me.UnboundTextBox = String(Len([MyField])-4, "*") & Right([MyField], 4)
End Sub
However, you also want to let your agents edit or view the full code later, if necessary. The best way to do this would be to set the OnEnter event for your unbound text box to pull the whole field value, so the agent can see and edit it - effectively the reverse of your OnUpdate event.
Private Sub UnboundTextBox_Enter()
Me.UnboundTextBox = Nz([Field1]) 'The Nz deals with Null errors
End Sub
I've used this with a field displaying SSN's and it works like a charm.
This is one of the stranger issues I have seen in MS Access. I have the following code in a continuous form:
Private Sub thisForm_BeforeUpdate(Cancel As Integer)
If Not Cancel Then
Debug.Print "pre-logging data changes..."
' here we need to doublecheck to see if any values changed.
' we simply iterate through the whole list, re-setting oldValue
' and newValue.
For Each control In thisForm.Section(acDetail).controls
If control.ControlType = acTextBox Or _
control.ControlType = acComboBox Or _
control.ControlType = acListBox Or _
control.ControlType = acOptionGroup Or _
control.ControlType = acCheckBox Then
Debug.Print control.Name
oldValues(control.Name) = control.oldValue
newValues(control.Name) = control.value
End If
Next
End If
End Sub
oldValues and newValues are Dictionary objects (although likely not related to the issue).
My form has 3 textbox controls, and a checkbox control. One of the text box controls is disabled, and is populated via the results of a simple inner join (to get the human readable name associated with a foreign key). The data source comes from the form's recordsource (no DLookup or anything is used).
If I edit one of the other two textbox controls, this code runs absolutely fine. HOWEVER, if I toggle the checkbox on the form, i get a runtime error 3251. In the watches window, I get the error again when i try to view the properties of "control". It shows the value of oldValue for the disabled control to be "Reserved Error".
If it did this consistently, I would think it was due to the control being disabled; but since it works without a problem when the other textboxes receive edits, and only breaks when the checkbox is toggled; I am stumped. I'm almost inclined to believe I found a bug in access, but I could use some extra input.
Anyone else every encounter an issue like this?
EDIT: Upon digging further, I found that in actuality only one of the 3 editable fields will not trigger this error. It holds string data. The other two controls hold a date value, and a yes/no value. Now I am even more confused.
i've got two ideas to that issue.
First one: If the RecordSource of your Form is an ODBC-Table thats linked to a SQL-Server then you should set a standard value for the CheckBox-Column. Otherwise it will try to set NULL to False and throw an error saying that somebody else edited the current record.
Second idea: Sometimes Access just has a little "hiccup" when it compiles the code. You could make a backup of your database and then try to decompile it using "C:\Program Files\Microsoft Office 2007\Office12\MSACCESS.EXE" "C:\yourFolder\yourDatabase.accdb" /decompile in the Run... Window (of course you have to insert the Path as it is on your machine). That often helps solving strange Problems.