Me.sfrmPosLineDetails_Subform.Requery
Me.SomeOtherControl.SetFocus ' change the name
Me.txtProductCode = Null
Me.txtProductCode.SetFocus
Although this was questioned by @BlueSpruce as being overkill. It is doing exactly what I said was happening.My next guess is that the focus is first set and then something causes the focus to move away. Such as a pending event or pending code. To test
Me.txtProductCode = Null
Me.txtProductCode.SetFocus
'Msgbox Me.activeControl ' at this point on txtproductcode
Me.TimerInterval = 1
Private Sub Form_Timer()
'MsgBox Me.ActiveControl.Name ' no longer on txtproductcode
Me.TimerInterval = 0
Me.txtProductCode.SetFocus
'MsgBox Me.ActiveControl.Name
End Sub
I think his subform became active when his parent form code executed 'With Me![sfrmPosLineDetails Subform].Form'.
As I said, this is as expected behavior and it has nothing to do with if the subform has focus or not set by the calling code.PS: As MajP has confirmed the problem is the moving of focus off the text box rather than onto a particular control. This might or might not be the subform control, so I'd expect the same behaviour however the row is inserted into the referencing table.
Private Sub txtProductCode_KeyDown(KeyCode As Integer, Shift As Integer)
Dim lngProdID As Long
Dim sReturn$, varValue As Variant
'Code
Me.sfrmPosLineDetails_Subform.Requery
txtProductCode = Null
' Me.txtProductCode.SetFocus 'No need for this since never loses focus'
End Sub
Adding a new record to the recordset in the subform does not move focus away from the main form?
Private Sub cmdAddEmployer_Click()
With Me.sfcEmployers.Form.Recordset
.AddNew
.Fields("ContactID") = Me.ContactID
.Fields("EmployerID") = 1
.Update
End With
Debug.Print Screen.ActiveControl.Name
End Sub
We all should have caught it earlier. You cannot hit return in a textbox and expect to stay in that textbox unless you change the EnterKeyBehavior property of the control.
I suggest you simply set focus to another control from the main form before you set focus to txtProductCode.
Public Sub txtProductCode_AfterUpdate()
...
Me.txtProductCode = Null
Me.CboCancelledInvoicedata.SetFocus
Me.txtProductCode.SetFocus
End Sub
There is one peculiarity that I am encountering with this approach though. Each time I enter something in the textbox and the AfterUpdate code adds that entry to the subform, it seems my Autonumber values skips one ID each time. For example, if I enter something that gets an ID value of 2, the next one I do gets the value of 4, and so on. I'll come back if I figure out why.
' ![RRP] = 0
.Recordset.Update
'immediately save the record
'DoCmd.RunCommand acCmdSaveRecord
If Me.Dirty = True Then
' Save the current record
Me.Dirty = False
End If
End With
'DoCmd.GoToRecord , , acNewRec
If you say so.I don't think anyone missed it, as we all know default behavior after a tab or enter exits a control
Public Sub txtProductCode_AfterUpdate()
Dim lngProdID As Long
Dim sReturn$, varValue As Variant
If Not (IsNull(mID)) Then
If Me.Dirty = True Then
Me.Dirty= False
End If
With Me![sfrmPosLineDetails Subform].Form.Recordset
.AddNew
!ItemSoldID = Me.ItemSoldID
![ProductID] = mID
![QtySold] = 1
sReturn = DLookup("ProductName & '|' & vatCatCd & '|' & dftPrc & '|' & VAT", _
"tblProducts", _
"BarCode = '" & Me.txtProductCode & "'")
varValue = Split(sReturn, "|")
![ProductName] = varValue(0)
![TaxClassA] = varValue(1)
![SellingPrice] = varValue(2)
![Tax] = varValue(3)
![ProductName] = DLookup("ProductName", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![TaxClassA] = DLookup("vatCatCd", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![SellingPrice] = DLookup("dftPrc", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![Tax] = DLookup("VAT", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
' ![RRP] = 0
.Update
End With
End If
Me.sfrmPosLineDetails_Subform.Requery
Me.txtProductCode = Null
Me.CboCancelledInvoicedata.SetFocus
Me.txtProductCode.SetFocus
End Sub
Code:If Me.Dirty = True Then Me.Dirty = False End If
Well spotted.I agree with you.This should be done before inserting a row into the referencing table. If a new order is being inserted in the parent form, referential integrity would otherwise be violated if the row has not yet been saved.
![ProductName] = varValue(0)
![TaxClassA] = varValue(1)
![SellingPrice] = varValue(2)
![Tax] = varValue(3)
![ProductName] = DLookup("ProductName", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![TaxClassA] = DLookup("vatCatCd", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![SellingPrice] = DLookup("dftPrc", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
![Tax] = DLookup("VAT", "tblProducts", "BarCode = '" & Me.txtProductCode & "'")
The code above simply erase data as you are enter the barcodeAs I said, this is as expected behavior and it has nothing to do with if the subform has focus or not set by the calling code.
We all should have caught it earlier. You cannot hit return in a textbox and expect to stay in that textbox unless you change the EnterKeyBehavior property of the control.
You can replicate this simply with any textbox.
Make a textbox in the after update of the textbox set the focus back to the text box. Make an update and Hit enter. It will go to the next control in the tab order as expected.
The enter causes the after update and immediately the exit occurs. That is how the access application works.
Instead of the timer you might be able to do away with the after update event.
You can set the enterkeybehavior to new line instead of default. This will keep it in the current textbox.
Code:Private Sub txtProductCode_KeyDown(KeyCode As Integer, Shift As Integer) Dim lngProdID As Long Dim sReturn$, varValue As Variant 'Code Me.sfrmPosLineDetails_Subform.Requery txtProductCode = Null ' Me.txtProductCode.SetFocus 'No need for this since never loses focus' End Sub
However with this you might also have to check on the on exit event to see if someone put in a bar code and then keyed out or moused out. Sounds unlikely.
on the AfterUpdate event of txtProduct, I Activate the Timer Event and
on the Timer Event, I clear TxtProduct and Setfocus to it.
Many thanks to arnlgp for clearly sorting out this and many thanks to all the contributors for your effort are also highly appreciated I have learnt a lot I hope even newcomers will benefit as well.on the AfterUpdate event of txtProduct, I Activate the Timer Event and
on the Timer Event, I clear TxtProduct and Setfocus to it.
Function GetLineNumber(F As Form, KeyName As String, KeyValue)
Dim RS As DAO.Recordset
Dim CountLines
On Error GoTo Err_GetLineNumber
Set RS = F.RecordsetClone
' Find the current record.
Select Case RS.fields(KeyName).Type
' Find using numeric data type key value.
Case dbInteger, dbLong, dbCurrency, dbSingle, dbDouble, dbByte
RS.FindFirst "[" & KeyName & "] = " & KeyValue
' Find using date data type key value.
Case dbDate
RS.FindFirst "[" & KeyName & "] = #" & KeyValue & "#"
' Find using text data type key value.
Case dbText
RS.FindFirst "[" & KeyName & "] = '" & KeyValue & "'"
Case Else
MsgBox "ERROR: Invalid key field data type!"
Exit Function
End Select
' Loop backward, counting the lines.
Do Until RS.BOF
CountLines = CountLines + 1
RS.MovePrevious
Loop
Bye_GetLineNumber:
' Return the result.
GetLineNumber = CountLines
Exit Function
Err_GetLineNumber:
CountLines = 0
Resume Bye_GetLineNumber
End Function
Do you really need to do the loop to get the line number?however, to return line numbers you need an addition module below
Function GetLineNumber(F As Form, KeyName As String, KeyValue)
' ...
' Loop backward, counting the lines.
' Do Until RS.BOF
' CountLines = CountLines + 1
' RS.MovePrevious
' Loop
CountLines = RS.AbsolutePosition + 1
Bye_GetLineNumber:
' Return the result.
GetLineNumber = CountLines
' ...
End Function
Though the code described above worked very well with the help of our valuable members , however, to return line numbers you need an addition module
SELECT COUNT(*) AS RowNumber, T1.CustomerID, T1.TransactionDate, T1.TransactionAmount
FROM Transactions AS T1 INNER JOIN Transactions AS T2
ON (T2.TransactionID<=T1.TransactionID OR T2.TransactionDate<>T1.TransactionDate)
AND (T2.TransactionDate<=T1.TransactionDate) AND (T2.CustomerID=T1.CustomerID)
GROUP BY T1.CustomerID, T1.TransactionDate, T1.TransactionAmount, T1.TransactionID;
SELECT DCOUNT("*","Transactions","CustomerID = " & CustomerID & "
AND TransactionDate <= #" & Format(TransactionDate,"yyyy-mm-dd") & "#
AND (TransactionID <= " & TransactionID & "
OR TransactionDate <> #" & Format(TransactionDate,"yyyy-mm-dd") & "#)")
AS RowNumber, CustomerID, TransactionDate, TransactionAmount
FROM Transactions
ORDER BY CustomerID, TransactionDate, TransactionID;