Help with sub-form and after update code

  • Thread starter Thread starter Rick Allison
  • Start date Start date
R

Rick Allison

I need some advice.

I've written a form with a sub-form. The sub-form has four text boxes with after update code. The code calculates numbers and displays the results on the main form.

The issue - when the user types real fast using the tab between each of the four fields the resulting calculation is not accurate. My guess is the logic is not done for the first text box by the time the user enters another value and perhaps even the next three values.

Is there a way to handle this rapid fire data entry and have the after update code work for each text box? I know, ask the user to slow down but you know users.

Does this make any sense?
 
Rick,
Please notice that almost everyone else that posts questions uses plain
text. This is deemed appropriate.

Would you care to share your code or what you are attempting to accomplish.
Fast typing shouldn't make a difference.

--
Duane Hookom
MS Access MVP
--

I need some advice.

I've written a form with a sub-form. The sub-form has four text boxes with
after update code. The code calculates numbers and displays the results on
the main form.

The issue - when the user types real fast using the tab between each of the
four fields the resulting calculation is not accurate. My guess is the
logic is not done for the first text box by the time the user enters another
value and perhaps even the next three values.

Is there a way to handle this rapid fire data entry and have the after
update code work for each text box? I know, ask the user to slow down but
you know users.

Does this make any sense?
 
Sorry about the rich-text format. Never really gave it much thought, just
knew to keep comments positive and stay away from nasty comments. That's
for the additional info.

Here's the two routines that execute "after update" on the sub-form. There
are four text boxes on the sub-form and the user can rapid fire, if you
well, between them. The code cannot keep up is my hunch but maybe you have
a much better explanation.

Public Sub txtDogFaultScore_AfterUpdate()

Const blnNQ As Boolean = False
Const blnQualified As Boolean = True

Dim intTotalNumberOfFaults As Integer
Dim intLimit As Integer
Dim strCurrentPenalties As String
Dim rst As DAO.Recordset
Dim frm As Form

' Calculate only if not absent Value "NO"
Set frm = Forms!frmAgilityScoring
If frm!grpAbsent Or frm!grpNoTimeEliminated Then
' do nothing
Else
' This code calculates the new number of faults for a given row in the
sub form
' if the number in the recordset is greater than the number on the
screen then
' a negative number is calculated. The number is negative because in
the
' routine that calculates the final score always adds so if a number of
faults
' is reduced the amount added to the final score must be negative to
reflect this
' reduction.
If IsNull(Me!txtDogFaultScore) Then
MsgBox "Number of Faults cannot be blank. Zero entered
automatically", vbInformation, _
"Negative Number"
Me!txtDogFaultScore = 0
End If
Set rst = Me.RecordsetClone
' What I learned here is that the recordset and form contain different
values.
rst.Bookmark = Me.Bookmark
strCurrentPenalties = rst!Penalties ' This value is used later
If rst!DogFaultScore > Me!txtDogFaultScore Then
intTotalNumberOfFaults = (Me!txtDogFaultScore * Me!txtFaultScore) - _
(rst!DogFaultScore * rst!FaultScore)
Else
intTotalNumberOfFaults = ((Me!txtDogFaultScore - rst!DogFaultScore) *
Me!txtFaultScore)
End If
rst.Close

Call CalculateTotalFaults(False, intTotalNumberOfFaults)

If CInt(Me!DogFaultScore) > _
CInt(Forms!frmAgilityScoring.fsubScoringPenalties!txtLimit) And _
CInt(Forms!frmAgilityScoring.fsubScoringPenalties!txtLimit) >= 0
Then
frm!txtQualified = blnNQ
Else
' look for other limits exceeded.
Set rst = Me.RecordsetClone
rst.MoveFirst
With rst
While Not .EOF
' As part of the software, a negative 1 (-1) indicates that there
are no limits
' imposed for this penalty. Therefore, we only check for
overlimit on those limits
' with positive numbers.
' Also, strCurrentPenalties contains the record that is current on
the form
' By not checking the recordsetclone for this record we can check
all others in the
' recordsetclone.
intLimit = GetLimit(!TitleEventDateID, !ScoringID)
If intLimit >= 0 Then
If rst!Penalties <> strCurrentPenalties Then
If CInt(!DogFaultScore) > intLimit Then
' a true value for overlimit means a limit was exceeded
frm!txtQualified = blnNQ
End If
End If
End If
.MoveNext
Wend
End With
End If
rst.Close
End If
End Sub

Sub CalculateTotalFaults(ByVal blnCheckOverLimit As Boolean, _
ByVal intPenalties As Integer)
' This subroutine calculates the total of all faults when scoring agility

On Error GoTo err_CalculateTotalFaults

Const blnNQ As Boolean = False
Const blnQualified As Boolean = True
Dim frm As Form
Dim intMaximumQualifyingScore As Integer
Dim intMinimumQualifyingScore As Integer
Dim intTotalScoringPenalties As Integer
Dim intTitleID As Integer

' txtTotalScoringPenalties is a screen field that holds the
' total score calculated from the subform
Set frm = Forms!frmAgilityScoring

intTotalScoringPenalties = frm!txtTotalScoringPenalties + _
intPenalties
' obtain the title for the Title Event Date
intTitleID = DLookup("TitleID", "tblTitleEvent", "TitleEventDateID = " &
frm!txtTitleEventDateID)

' First find the minimum and maximum score for this trial and class

' Here's where the score is calculated.
' txtTimeFaults is a screen field that is calculated in
CalculateTimeFaults subroutine.
' intTotalScoringPenalties is the temporary field used in this subroutine
to store
' the values from the sub form.
' For the type of title add or subtract the scores
Select Case DLookup("AddSubtractScoring", "tblTitle", "TitleID = " &
intTitleID)
Case "Subtract"
intMaximumQualifyingScore = intMaximumQualifyingScore - _
frm!txtTimeFaults _
- intTotalScoringPenalties
' populate the screen with final score and total faults
' If the total is negative only display 0
frm!txtDogScore = IIf(intMaximumQualifyingScore < 0, 0,
intMaximumQualifyingScore)
Case "Add"
intMaximumQualifyingScore = intMaximumQualifyingScore + _
frm!txtTimeFaults _
+ intTotalScoringPenalties
frm!txtDogScore = intMaximumQualifyingScore
End Select
' populate the field showing the total number of faults.
frm!txtTotalFaults = frm!txtTimeFaults + intTotalScoringPenalties

' Look at the final score and determine if the dog NQed
' Always assume qualified and then check for Not Qualified score
' do this check only for the normal AKC agility 2001-12-16
frm!txtQualified = blnQualified
If intMaximumQualifyingScore < intMinimumQualifyingScore Then
frm!txtQualified = blnNQ
Else
' Check to see if any over limit conditions exist when changing the time
only
' The over limit condition for other than the time will be checked in the
subform
If blnCheckOverLimit Then
If OverLimit Then
frm!txtQualified = blnNQ
End If
End If
End If
exit_CalculateTotalFaults:
Exit Sub
err_CalculateTotalFaults:
Call Handle_Err(Err.Number, Err.Description, "Subroutine
CalculateTotalFaults")
Resume exit_CalculateTotalFaults
End Sub
 
My guess is that the subform records aren't being saved prior to the code
running. I would add Me.Dirty = False early in the code to save the records.

--
Duane Hookom
MS Access MVP
--

Rick Allison said:
Sorry about the rich-text format. Never really gave it much thought, just
knew to keep comments positive and stay away from nasty comments. That's
for the additional info.

Here's the two routines that execute "after update" on the sub-form.
There
are four text boxes on the sub-form and the user can rapid fire, if you
well, between them. The code cannot keep up is my hunch but maybe you
have
a much better explanation.

Public Sub txtDogFaultScore_AfterUpdate()

Const blnNQ As Boolean = False
Const blnQualified As Boolean = True

Dim intTotalNumberOfFaults As Integer
Dim intLimit As Integer
Dim strCurrentPenalties As String
Dim rst As DAO.Recordset
Dim frm As Form

' Calculate only if not absent Value "NO"
Set frm = Forms!frmAgilityScoring
If frm!grpAbsent Or frm!grpNoTimeEliminated Then
' do nothing
Else
' This code calculates the new number of faults for a given row in the
sub form
' if the number in the recordset is greater than the number on the
screen then
' a negative number is calculated. The number is negative because in
the
' routine that calculates the final score always adds so if a number
of
faults
' is reduced the amount added to the final score must be negative to
reflect this
' reduction.
If IsNull(Me!txtDogFaultScore) Then
MsgBox "Number of Faults cannot be blank. Zero entered
automatically", vbInformation, _
"Negative Number"
Me!txtDogFaultScore = 0
End If
Set rst = Me.RecordsetClone
' What I learned here is that the recordset and form contain different
values.
rst.Bookmark = Me.Bookmark
strCurrentPenalties = rst!Penalties ' This value is used later
If rst!DogFaultScore > Me!txtDogFaultScore Then
intTotalNumberOfFaults = (Me!txtDogFaultScore * Me!txtFaultScore) - _
(rst!DogFaultScore * rst!FaultScore)
Else
intTotalNumberOfFaults = ((Me!txtDogFaultScore - rst!DogFaultScore) *
Me!txtFaultScore)
End If
rst.Close

Call CalculateTotalFaults(False, intTotalNumberOfFaults)

If CInt(Me!DogFaultScore) > _
CInt(Forms!frmAgilityScoring.fsubScoringPenalties!txtLimit) And _
CInt(Forms!frmAgilityScoring.fsubScoringPenalties!txtLimit) >= 0
Then
frm!txtQualified = blnNQ
Else
' look for other limits exceeded.
Set rst = Me.RecordsetClone
rst.MoveFirst
With rst
While Not .EOF
' As part of the software, a negative 1 (-1) indicates that there
are no limits
' imposed for this penalty. Therefore, we only check for
overlimit on those limits
' with positive numbers.
' Also, strCurrentPenalties contains the record that is current
on
the form
' By not checking the recordsetclone for this record we can check
all others in the
' recordsetclone.
intLimit = GetLimit(!TitleEventDateID, !ScoringID)
If intLimit >= 0 Then
If rst!Penalties <> strCurrentPenalties Then
If CInt(!DogFaultScore) > intLimit Then
' a true value for overlimit means a limit was exceeded
frm!txtQualified = blnNQ
End If
End If
End If
.MoveNext
Wend
End With
End If
rst.Close
End If
End Sub

Sub CalculateTotalFaults(ByVal blnCheckOverLimit As Boolean, _
ByVal intPenalties As Integer)
' This subroutine calculates the total of all faults when scoring agility

On Error GoTo err_CalculateTotalFaults

Const blnNQ As Boolean = False
Const blnQualified As Boolean = True
Dim frm As Form
Dim intMaximumQualifyingScore As Integer
Dim intMinimumQualifyingScore As Integer
Dim intTotalScoringPenalties As Integer
Dim intTitleID As Integer

' txtTotalScoringPenalties is a screen field that holds the
' total score calculated from the subform
Set frm = Forms!frmAgilityScoring

intTotalScoringPenalties = frm!txtTotalScoringPenalties + _
intPenalties
' obtain the title for the Title Event Date
intTitleID = DLookup("TitleID", "tblTitleEvent", "TitleEventDateID = " &
frm!txtTitleEventDateID)

' First find the minimum and maximum score for this trial and class

' Here's where the score is calculated.
' txtTimeFaults is a screen field that is calculated in
CalculateTimeFaults subroutine.
' intTotalScoringPenalties is the temporary field used in this
subroutine
to store
' the values from the sub form.
' For the type of title add or subtract the scores
Select Case DLookup("AddSubtractScoring", "tblTitle", "TitleID = " &
intTitleID)
Case "Subtract"
intMaximumQualifyingScore = intMaximumQualifyingScore - _
frm!txtTimeFaults _
- intTotalScoringPenalties
' populate the screen with final score and total faults
' If the total is negative only display 0
frm!txtDogScore = IIf(intMaximumQualifyingScore < 0, 0,
intMaximumQualifyingScore)
Case "Add"
intMaximumQualifyingScore = intMaximumQualifyingScore + _
frm!txtTimeFaults _
+ intTotalScoringPenalties
frm!txtDogScore = intMaximumQualifyingScore
End Select
' populate the field showing the total number of faults.
frm!txtTotalFaults = frm!txtTimeFaults + intTotalScoringPenalties

' Look at the final score and determine if the dog NQed
' Always assume qualified and then check for Not Qualified score
' do this check only for the normal AKC agility 2001-12-16
frm!txtQualified = blnQualified
If intMaximumQualifyingScore < intMinimumQualifyingScore Then
frm!txtQualified = blnNQ
Else
' Check to see if any over limit conditions exist when changing the time
only
' The over limit condition for other than the time will be checked in
the
subform
If blnCheckOverLimit Then
If OverLimit Then
frm!txtQualified = blnNQ
End If
End If
End If
exit_CalculateTotalFaults:
Exit Sub
err_CalculateTotalFaults:
Call Handle_Err(Err.Number, Err.Description, "Subroutine
CalculateTotalFaults")
Resume exit_CalculateTotalFaults
End Sub
 
I did not know that setting me.dirty = false would save records.

How would that speed up the code?

--
Rick Allison
Duane Hookom said:
My guess is that the subform records aren't being saved prior to the code
running. I would add Me.Dirty = False early in the code to save the
records.
 
My thought was that the records were not saved in the form or subform prior
to your long code running.

You also had a couple domain aggregate functions that are notoriously slow.
 
"Domain Aggregate functions?" Which ones? I'm not familiar with this
terminology.

Thanks,
 
Ah yes. The bad DLookup. Is there a better / faster way to do DLookup?
I've read a great deal about this but have not really seen a final answer.
I've seen tools written by others but never really used them.

What's your take?
 
I believe queries with subqueries might work more efficiently since they can
take advantage of indexes.
 
Back
Top