Doing research on the Web is like using a library assembled piecemeal by pack rats and vandalized nightly. - Roger Ebert

Top Ten Tags

Who's Online

In this article I'll show you how to highlight edited fields on a form and help you understand some of the control and form events (see additional links for information on all the events.).

The first thing we need to understand is what are events. For the control (e.g. textboxes) events, we'll be focusing on the Change and BeforeUpdate events. [Note: Controls and Forms have many events in common, but there are some that are specific to each.]

Event Description
Change Occurs when the content in control is being editted
BeforeUpdate Occurs before data in a control is updated


In order to be able to know if a field value has changed we need some way to compare the before and after value of the field. For that we will use the .Value and .OldValue property.

Property Description
Value Current/Editted value of a bound control (this is not the same a the value of the record's field, but we'll get to that)
OldValue Uneditted value of a bound control (this is the value of the current unedited record)


When you edit a value in a control, you're only changing the value stored in that control not the value of the underlying bound field in the record. The change to the record (and its fields) isn't saved until you save the record. Once more, a record is a collection of fields; changes to the fields are not saved until the record is saved. So the record value (.OldValue) and the editted value (.Value) are available for you to compare only before you save the record. If no changes were made, the values are the same.

[Note: You can't directly use Null values in comparison, e.g. Null = Null and Null = 1 will both return Null instead of a TRUE or FALSE.]

This is what will allow us to highlight fields that have been edited and notifiy the user of any changes in value.

The heart of my approach is a subroutine that can be called from any control, i.e. sHighlightEdits(). You pass a contol the the subroutine. It checks to see if they are different, and if the value has been changed it will change the background to a highlighted color.

[Note: If you've added conditional formatting to change a control's backcolor while it has focus, that takes precedence over the highlighting code I'm presenting in this article.]


The one line of code you need to add to each control's AfterUpdate (happens after change to control, not record, is made) event is:

sHighlightEdits Screen.ActiveControl

VBA Code

Private Sub sHighlightEdits(ctlControl As Control)

    '*******************************************************************************************
    'Description: Code to highlight data entry form controls values that have been changed
    '© Azli Hassan, http://azlihassan.com/apps
    '*******************************************************************************************

    On Error GoTo ErrMsg

    Dim ctl As Control, blnChanged As Boolean

    'No need to highlight for new record.
    If Me.NewRecord Then Exit Sub
    
    Set ctl = ctlControl

    With ctl
		'Add more control types as needed
		'https://msdn.microsoft.com/VBA/Access-VBA/articles/label-controltype-property-access
        If .ControlType = acTextBox _
           Or .ControlType = acComboBox Then
            If .Enabled Then 'If it's disabled then there wouldn't be any ability to edit
                Debug.Print "ctl.Name = " & .Name
                'Check if value has changed
                'First, check that BOTH aren't null
                If Not (IsNull(.Value) And IsNull(.OldValue)) Then
					'Both are not Null
                    'Check that one is null (if so, went from a value to a null or vice versa)
                    If IsNull(.Value) Or IsNull(.OldValue) Then
                        blnChanged = True
                    Else
                        'Neither are null, so check if they are different
                        blnChanged = .Value <> .OldValue
                    End If
                Else
                    'Both are null, so they are the same
                    'Can't compare Null values. Go ahead and try the following:
                    ' - Debug.Print (Null = Null)
                    ' - Debug.Print (Null = 1)
                    ' - Debug.Print (1 = 1)
                    blnChanged = False
                End If
                'Highlight if value has changed
                If blnChanged Then
                    .BackColor = cHighlightColor
                Else
                    'Get original backcolor from the end of controls .Tag property
                    .BackColor = GetBackcolorCTag(.Tag)
                End If
            End If
        End If
    End With
    
ExitHere:
    Exit Sub

ErrMsg:
    MsgBox "An error has occurred in sHighlightEdits()." & vbNewLine & vbNewLine & _
           "Error Number:" & Err.Number & " (" & Err.Description & ").", vbCritical, "Error!"
    Debug.Print "sUpdateControlTipTextLabel()"
    Debug.Print "Err.Number = " & Err.Number
    Debug.Print "Err.Description = " & Err.Description
    Resume ExitHere
End Sub

There are a few things to know about using my code:

  • Need to set up a few module-level constants.
  • Understand that each control's Tag property will be used, so much be sure that you have enough space to store the the original backcolor in the tag and adapt any code you may have that uses the .Tag property acccordly as it is limited to a string expression up to 2048 characters long.
  • Need to add event procedure code to certain events for all the controls that you want to highlight changes. Luckliy, it's the exact same line of code for each control.

When the form is opened, code in the form's Open event will add each control's current backcolor at the end of the .Tag property (see sample file for the code). A 'delimiter' is used to demark where to find the highlight color in the .Tag property.

Private Const cClrDelimiter As String = "#bc" 'Used to find stored current control backcolor in control's tag
Private Const cHighlightColor As Long = vbYellow 'Color used to highlight an editted control

A function, GetBackcolorCTag(), is used to strip the original color from the .Tag property when resetting the color back to the original color, i.e. unhighllighting.

Additional features included in sample file

I added code that unhighlights all the fields if the forms's Undo event is triggered, e.g. pressing ESC twice to undo all of the changes to a record (the first ESC only undoes the change in the field with focus if a change was made. If not, only one ESC keypress is needed.).

I've also added code, using a subroutine called sUpdateControlTip() called from the Change / GotFocus / Lostfocus control events, that changes text in a label (lblControlTip) to show you:

  • What data field you're currently on, i.e. has focus. This uses the 'ControlTip Text' of the control as the text to be displayed.


  • Whether you're currently editing the field, using the Change() event.


  • Once you've made a change to the control (i.e. move to another control), and then move back to that control, the text will say what change you've made to the value (if any).

Just before you save any record changes by moving to another record another subroutine, sNotifyEdits(), will run that notifies you of the changes made using the form's BeforeUpdate event (happens before record is saved so that .OldValue and .Value are available to compare the before and after values). As this uses a VBA MsgBox to notify the user, it is limited to 'approximately 1024 characters, depending on the width of the characters used', so if you have many fields you may want to change it to only say which fields have changed. [Note: vbNewLine counts as 2 characters]

In a future article, I'll show you how to use more of the form events to control enabling/disabling of record navigation buttons and record operation (Add, Delete, Save, and Undo) buttons. The sample file for this article has a simple version of enabling/disabling code, but I didn't include save or undo buttons because that's beyond the intended scope of this article.

Caveat

While this method also works for continuous / tabular forms, it will highlight the field for ALL visible records since formatting applied to a control applies to that control for all records (unlike the built-in conditional formatting feature).

Additional Links