DoEvents vs. Repaint in Microsoft Access

This is bonus 1 of a multi-part series on the DoEvents function.


In part 3 of my series of articles exploring the DoEvents function, I showed the following demonstration of the difference between running a loop without a DoEvents call vs. one with a DoEvents call.

Microsoft Access is single-threaded.  The code and the user interface both run on the same thread.  If you want to provide form updates during a long-running process (like for a custom progress meter form), you need to explicitly give the UI a chance to update itself.

Question from Joakim Dalby

On LinkedIn, Joakim Dalby asked a follow-up question about that article:

Could Me.Refresh or Me.Repaint or Me.Recalc replace your DoEvents in your test form?

My response on LinkedIn

I just tested these three options using my demo form (https://nolongerset.com/doevents-demo/).  

Me.Refresh had no effect.  

Me.Recalc resulted in the Status Bar showing "Calculating...", but had no other obvious effect.

Me.Repaint *did* result in the UI being updated.  However, it did not allow the Cancel button to work.

So, in certain situations, Me.Repaint could be preferable to DoEvents, as it is more precise in what it does.  Good call!

The Form Repaint Method

From the official Microsoft docs:

The Repaint method completes any pending screen updates for a specified form. When performed on a form, the Repaint method also completes any pending recalculations of the form's controls.

The documentation goes on to clarify the difference between the Repaint method and the Refresh method:

Don't confuse the Repaint method with the Refresh method, or with the Refresh command on the Records menu. The Refresh method and the Refresh command show changes that you or other users have made to the underlying record source for any of the currently displayed records in forms and datasheets. The Repaint method simply updates the screen when repainting has been delayed while Access completes other tasks.

The Recalc method simply forces a recalculation of any calculated controls.

Updated demo

I updated my previous demonstration to show the effect of calling Me.Repaint instead of DoEvents within the loop.

Me.Repaint updates the current count, but the Cancel click does not get processed.

Here is the code-behind for the above form:

Option Compare Database
Option Explicit

#If VBA7 Then
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

Private mUserCanceled As Boolean

Private Sub RunLoop(YieldCommand As String)
    mUserCanceled = False
    DoCmd.Hourglass True
    Me.tbCount.Value = 0
    
    Dim i As Long
    For i = tbStart.Value To tbEnd.Value
        If mUserCanceled Then Exit For
        Sleep tbDelay.Value
        Me.tbCount.Value = i
        Select Case YieldCommand
        Case "Nothing"
            'Do nothing to yield execution
        Case "Repaint"
            Me.Repaint
        Case "DoEvents"
            DoEvents
        End Select
    Next i
    DoCmd.Hourglass False
End Sub

Private Sub btnNoDoEvents_Click()
    RunLoop "Nothing"
End Sub

Private Sub btnRepaint_Click()
    RunLoop "Repaint"
End Sub

Private Sub btnWithDoEvents_Click()
    RunLoop "DoEvents"
End Sub

Private Sub btnCancel_Click()
    mUserCanceled = True
End Sub

If you want to play with the code yourself, there is a sample database available here: TestDoEvents-v2.zip


Referenced articles

Demystifying DoEvents
The DoEvents function may be the single most misunderstood piece of code in the entire VBA language. In this series of articles, I’ll try to remedy that.
When (or Should I Say, How Often) to Call DoEvents
Too few calls to DoEvents, and your app may appear to be ”(Not Responding).” Too many calls to DoEvents, and your app will run slow. Let’s Goldilocks this thing.

External references

Mike Wolfe on LinkedIn: When (or Should I Say, How Often) to Call DoEvents
Too few calls to DoEvents, and your app may appear to be ”(Not Responding).” Too many calls to DoEvents, and your app will run slow. Let’s Goldilocks...
This link is to the LinkedIn discussion of the article, not the article itself.
Form.Repaint method (Access)
Form.Refresh method (Access)
Form.Recalc method (Access)

Image by Prashant Sharma from Pixabay