Microsoft Access VBA Tutorials for self-paced learning, Class Modules, SQL Techniques, and AI Integration Guides.

Showing posts with label Array. Show all posts
Showing posts with label Array. Show all posts

Access Form Control Arrays and Event-2

Control Arrays and Events-2.

Last week, we learned how to create a Class Object Array for TextBoxes on the Form. The built-in AfterUpdate and LostFocus events raised from the TextBoxes on the Form are captured by their corresponding elements in the Class Object Array. Each element then executes its own AfterUpdate() or LostFocus() subroutine, instead of running the code within the Form’s Class Module as we normally would.

For example, the AfterUpdate event of the first TextBox is captured by the first element of the Class Object Array, and its AfterUpdate () subroutine is executed there. In the same way, events from other TextBoxes are also handled by their respective Class Object Array elements.

If you are new to this topic, please refer to the earlier pages using the links below to understand the step-by-step transition of code from one stage to the next.

  1. withevents Button Combo List TextBox Tab
  2. Access Form Control Arrays and Event Capturing

The AfterUpdate and LostFocus event handler code we wrote earlier in the Class Module was generic in nature and applied to all TextBox controls on the Form. These were test subroutines created solely to experiment whether the events triggered from each TextBox on the Form were being correctly captured by their respective Class Module array elements.

Data Validation Checks

Now, it’s time to define specific data validation rules for each TextBox on the form and ensure that the user is notified whenever a rule is violated.

To make sure these rules are clear, I’ve placed descriptive labels above each Text Box on the form. These labels indicate how the values entered in the TextBoxes will be validated within the Class Module array through their AfterUpdate and LostFocus events.

An image of the form, showing the TextBoxes along with their corresponding validation rule labels, is provided below.


    Note: This setup is intended purely for demonstration purposes, so the validation rules are not strictly enforced. The second TextBox accepts any type of input—whether text, numbers, or other characters. The Mobile Number field, however, checks only the length of the entered value. Additionally, the Mobile Number TextBox has an Input Mask applied to restrict input to digits only.

  1. The first TextBox accepts only values between 1 and 5. Any value outside this range triggers an error message.

  2. The second TextBox is validated in the LostFocus event to ensure it is not left blank. If it is empty, an error message is displayed, and a sample string is inserted automatically.

  3. The third TextBox accepts text or numbers up to 10 characters long. Any extra characters beyond this limit are removed, and the field is updated accordingly. If left blank, no error is shown.

  4. The fourth TextBox is a date field. Any date later than today is considered invalid.

  5. The last TextBox accepts only a 10-digit number.

The Class Module Changes.

We will write the VBA code for the above simple validation checks in the class module.

The earlier version of the VBA code in the class module  ClstxtArray1 is given below for reference.

Option Compare Database
Option Explicit

Public WithEvents Txt As Access.TextBox

Private Sub Txt_AfterUpdate()
Dim txtName As String, sngval As Single
Dim msg As String

txtName = Txt.Name
sngval = Nz(Txt.Value, 0)

msg = txtName & " _AfterUpdate. :" & sngval
MsgBox msg, vbInformation, Txt.Name

End Sub

Private Sub Txt_LostFocus()
Dim tbx As Variant
tbx = Nz(Txt.Value, "")

If Len(tbx) = 0 Then
  MsgBox Txt.Name & " is Empty.", vbInformation, Txt.Name
End If
End Sub

The Event-based Sub-Routine

Check the Txt_AfterUpdate() event procedure. This single event handler in the class module receives the AfterUpdate event from all the text boxes on the form. The txt.Name property identifies which text box triggered the event, while the txt.Value property provides the value entered in that text box. Using these two properties, you can write specific validation logic for the contents of each text box.

The text box validation sample VBA code of the txt_AfterUpdate() Event Sub-routine is given below.

Private Sub Txt_AfterUpdate()
Dim txtName As String, varVal As Variant
Dim msg As String

txtName = Txt.Name
msg = ""
Select Case txtName
    Case "Text0"
        varVal = Nz(Txt.Value, 0)
        If varVal < 1 Or varVal > 5 Then
           msg = "Valid Value Range 1-5 only: " & varVal
        End If
    Case "Text8"
        ' validation in OnLostFocus Event
    Case "Text10"
        varVal = Nz(Txt.Value, "")
        If Len(varVal) > 10 Then
           msg = "Max 10 Characters Only. " & varVal
           Txt.Value = Left(varVal, 10)
        End If
    Case "Text12"
        varVal = DateValue(Txt.Value)
        If varVal > Date Then
          msg = "Future Date Invalid. " & varVal
        End If
    Case "Text14"
        varVal = Trim(Str(Nz(Txt.Value, 0)))
        If Len(varVal) <> 10 Then
          msg = "Invalid Mobile Number: " & varVal
        End If
End Select

If Len(msg) > 0 Then
    MsgBox msg, vbInformation, Txt.Name
End If

End Sub

The text box name (Txt.Name) received from the AfterUpdate Event is checked in the Select Case. . . End Select structure.  Depending on the text box name and the TextBox value (Txt.Value), the validation check is performed; if Invalid, an appropriate message is displayed.

On the Form_Load() Event Procedure, we have added the OnLostFocus() Event only for TextBox8 on the form.  When the insertion point leaves this text box, the LostFocus Event fires and is captured in the Private Sub txt_LostFocus()  subroutine of the class module.  If the TextBox is empty, the sample text string “XXXXXXXXXX” is inserted into TextBox8, followed by an error message.

The LostFocus subroutine is given below:

Private Sub Txt_LostFocus()
Dim tbx As Variant, msg As String

tbx = Nz(Txt.Value, "")

msg = ""
If Len(tbx) = 0 Then
  msg = Txt.Name & " cannot leave it Empty."
  Txt.Value = "XXXXXXXXXX"
End If

If Len(msg) > 0 Then
   MsgBox msg, vbInformation, Txt.Name
End If

End Sub

Here, we are not testing for TextBox8, as we did in the AfterUpdate() event procedure, because we have not added the LostFocus Event for any other TextBox. 

Did you notice that the statement Txt.value = "XXXXXXXXXX" writes the string back to the same TextBox from which the event was captured? But what if we need to access another control on the form to read or write data there?

To achieve this, we must introduce a Form object property in the class module. We will implement this along with the upcoming code changes, as part of our future plan is to move all actions from the form module to the class module.

The full VBA Code of the Class Module: ClsTxtArray1_2 is given below:

Option Compare Database
Option Explicit

Public WithEvents Txt As Access.TextBox

Private Sub Txt_AfterUpdate()
Dim txtName As String, varVal As Variant
Dim msg As String

txtName = Txt.Name
msg = ""
Select Case txtName
    Case "Text0"
        varVal = Nz(Txt.Value, 0)
        If varVal < 1 Or varVal > 5 Then
           msg = "Valid Value Range 1-5 only: " & varVal
        End If
    Case "Text8"
        ' validation in OnLostFocus Event
    Case "Text10"
        varVal = Nz(Txt.Value, "")
        If Len(varVal) > 10 Then
           msg = "Max 10 Characters Only. " & varVal
           Txt.Value = Left(varVal, 10)
        End If
    Case "Text12"
        varVal = DateValue(Txt.Value)
        If varVal > Date Then
          msg = "Future Date Invalid. " & varVal
        End If
    Case "Text14"
        varVal = Trim(Str(Nz(Txt.Value, 0)))
        If Len(varVal) <> 10 Then
          msg = "Invalid Mobile Number: " & varVal
        End If
End Select

If Len(msg) > 0 Then
    MsgBox msg, vbInformation, Txt.Name
End If

End Sub

Private Sub Txt_LostFocus()
Dim tbx As Variant, msg As String

tbx = Nz(Txt.Value, "")

msg = ""
If Len(tbx) = 0 Then
  msg = Txt.Name & " cannot leave it Empty."
  Txt.Value = "XXXXXXXXXX"
End If

If Len(msg) > 0 Then
   MsgBox msg, vbInformation, Txt.Name
End If

End Sub

The Form Module VBA Code

The form module code remains unchanged from last week’s example, except that the class module name has been updated to ClstxtArray1_2.

I maintain the class module code from earlier articles as separate versioned copies, which is why the class module name has changed here.

Additionally, I made a minor change in the form module code for the TextBox8 control — it now raises only the LostFocus event. In the earlier version, the code triggered both the AfterUpdate and LostFocus events.

Option Compare Database
Option Explicit

Private Ta() As New ClsTxtArray1_2

Private Sub Form_Load()
Dim cnt As Integer
Dim ctl As Control

For Each ctl In Me.Controls
  If TypeName(ctl) = "TextBox" Then
     cnt = cnt + 1
     ReDim Preserve Ta(1 To cnt)
     Set Ta(cnt).Txt = ctl
     
     If ctl.Name = "Text8" Then
       Ta(cnt).Txt.OnLostFocus = "[Event Procedure]"
     Else
       Ta(cnt).Txt.AfterUpdate = "[Event Procedure]"
     End If    
  End If
Next
End Sub

Downloads

We have now moved all the event-handling code—normally written in the form’s class module—into a separate class module, keeping all the underlying actions completely hidden from the user.

However, if you look at the current Form_Load() event procedure, you’ll notice that there’s still quite a bit of code left in the form module.

In the coming weeks, we’ll explore techniques to shift almost all this remaining code into the Standalone Class Module, leaving only three or four lines in the Form Module.

In the meantime, you can download the demo database from the links below, try it out, and study the code to understand how it works.



Links to WithEvents ...Tutorials.

  1. WithEvents MS-Access Class Module Tutorial
  2. WithEvents and Defining Your Own Events
  3. withevents Button Combo List TextBox Tab
  4. Access Form Control Arrays and Event Capturing
  5. Access Form Control Arrays and Event-2
  6. Access Form Control Arrays and Event-3
  7. WithEvents in Class Module for Sub-Form TextBox Events
  8. WithEvents in Class Module and Data Entry
  9. WithEvents and Access Report Event Sink
  10. WithEvents and Report Lines Hiding
  11. WithEvents and Report Lines Highlighting
  12. Withevents TextBox and Command Button Arrays
  13. Withevents TextBox CommandButton Dictionary
  14. Withevents and all Form Control Types

Share:

Access Form Control Arrays and Event Capturing

Control Arrays and Event Capturing.

Forms will have several objects of the same type.  For example, there will be several TextBoxes on the Form.  It is not possible to declare separate TextBox Properties in a Class Module to capture Events from each one. 

The easiest technique is something like the following steps:

  1. Create a Class Module with a single Text Box object property.

  2. Define separate subroutines in the Class Module—such as AfterUpdate, LostFocus, and others—to handle the respective events triggered by Text Box controls on the Form.

  3. In the Form’s module (or in another dedicated Class Module), create an array of these Class Module objects, assigning one class object instance to each Text Box control on the Form.

  4. When a built-in event is raised from a particular Text Box on the Form, it will be captured by the corresponding class object in the array and executed through its event-handling subroutine.

Sample Demo Project

Let us start with a simple example.

  1. Create a new Class Module and change its Name Property Value to clsTxtArray1.

  2. Copy and paste the following VBA Code into the Class Module and save it:

    Option Compare Database
    Option Explicit
    
    Public WithEvents Txt As Access.TextBox
    
    Private Sub Txt_AfterUpdate()
    Dim txtName As String, sngval As Single
    Dim msg As String
    
    txtName = Txt.Name
    sngval = Nz(Txt.Value, 0)
    
    msg = txtName & " _AfterUpdate. :" & sngval
    MsgBox msg, vbInformation, Txt.Name
    
    End Sub
    

    Declare the Text Box Object Txt with Public scope to avoid the Get and Set Property Procedures for the time being, to keep the Code in the Class Module simple.

    The AfterUpdate() Event Procedure will execute when that Event of the Text Box fires on the Form.

  3. Create a new Form, insert a single Text Box on the Form, and save the Form with the name frmTxtArray1.

    An image of the sample form is given below.


  4. Open the Form in Design View and display the form's Code Module.
  5. Copy and Paste the following VBA Code into the Form Module:

    Option Compare Database
    Option Explicit
    
    Private ta() As New ClsTxtArray1
    
    Private Sub Form_Load()
    Dim cnt As Integer
    Dim ctl As Control
    
    For Each ctl In Me.Controls
      If TypeName(ctl) = "TextBox" Then
         cnt = cnt + 1
         ReDim Preserve ta(1 To cnt)
         Set ta(cnt).Txt = ctl
         ta(cnt).Txt.AfterUpdate = "[Event Procedure]"
      End If
    Next
    End Sub

    The VBA Code Line by Line

    In the global declaration area, the ClsTxtArray1 Class is instantiated as an empty Array Object.

    The real action is in the Form_Load() Event Procedure.

    Two Variables, Count (cnt) and Control (ctl), are declared.

    The For Each ... Next Loop is set to scan the Form for all Control Types on the Form, and identify the required control type: TextBox.

    If the Control TypeName is TextBox, then the cnt Variable is incremented by one. The ta Array is re-dimensioned for 1 to cnt iterations, preserving the earlier elements of data, if any.

    The statement 'Set ta(cnt).Txt = ctl' assigns the current Class Object Array element’s txt Property with the TextBox Control.

    The next line 'ta(cnt).Txt.AfterUpdate' = "[Event Procedure]"' enables the TextBox’s AfterUpdate Event, so that it can be captured in the Private Sub txt_AfterUpdate() sub-routine of the ta(cnt) instance of the ClsTxtArray1 Array element.

  6. If you are through with the above lines of Code, then save and close the Form.

  7. Sample Data Entry

    Open the Form in normal view.

  8. Enter some numeric Value into the Text Box and press the Tab Key. 

    A message box displays the entered value.  A sample test run image is given below.

    Check the MsgBox image, with event-related info showing in there.

    The TexBox Name is shown in the Title area, from where the AfterUpdate Event is captured.  The message line indicates that it is run from the AfterUpdate subroutine, and the value entered into the TextBox is displayed at the end of the line.

    Adding More Controls on Form

  9. Close the Form and open it in Design View.

  10. Add a few more TextBoxes, anywhere you like on the Form.

  11. Save and Close the Form.

    A sample Image of the changed Form is given below.

  12. Open the Form in Normal View.

  13. Enter some numeric value in any newly added text box and press the Tab Key.

    When you do this, the MsgBox will pop up, displaying messages like the earlier one. It will contain the TextBox Name and the number entered in the Text Box.

  14. Try out other TextBoxes in this way. Add more TextBoxes, if you like, and try out whether the newly added TextBoxes also respond to the AfterUpdate event.

The After Update Event fires only when you enter a value or edit an existing value and leave the Text Box.

Adding the LostFocus Event

But what if a particular Text Box must not be left blank when the cursor moves away from it (on the LostFocus event) without entering any value?

In such a case, when the insertion point leaves that Text Box, the Form should trigger its LostFocus event. This event must then be captured in the Class Module, and a message should be displayed if the Text Box is empty.

To implement this behavior, we need to make corresponding changes in both the Form Module and the Class Module.

In the Form_Load() Event Procedure, check whether TextBox8 (on my Form, the second TextBox at the left) is the current control, then add 'ta(cnt).Txt.OnLostFocus' = "[Event Procedure]"  to trigger the LostFocus() Event on TextBox8. 

Add the following lines to the Form_Load() Event Procedure, replacing Text8 with the Text Box name from your Form.

If ctl.Name = "Text8" Then
   ta(cnt).Txt.OnLostFocus = "[Event Procedure]"
End If

The current control's name is Text8; then 'ta(cnt).Txt.OnLostFocus' Event is also set to invoke this Event.  So Text8 will fire both AfterUpdate and LostFocus Events.   

The changed Form_Load() Event Procedure Code is given below:

Private Sub Form_Load()
Dim cnt As Integer
Dim ctl As Control

For Each ctl In Me.Controls
  If TypeName(ctl) = "TextBox" Then
     cnt = cnt + 1
     ReDim Preserve ta(1 To cnt)
     Set ta(cnt).Txt = ctl
     ta(cnt).Txt.AfterUpdate = "[Event Procedure]"
     
     If ctl.Name = "Text8" Then
       ta(cnt).Txt.OnLostFocus = "[Event Procedure]"
     End If
     
  End If
Next
End Sub

A Subroutine for the LostFocus Event is required in the ClstxtArray1 Class Module to capture the Event from the Text8 Text Box.

The Subroutine code to handle the LostFocus Event is given below:

Private Sub Txt_LostFocus()
Dim tbx As Variant
tbx = Nz(Txt.Value, "")

If Len(tbx) = 0 Then
  MsgBox Txt.Name & " is Empty.", vbInformation, Txt.Name
End If
End Sub

If some value is entered into the Text8 TextBox, then the MsgBox will not appear for the LostFocus Event.  If the TextBox8 is empty, then the LostFocus Event will fire.  The full Class Module Code is given below:

Option Compare Database
Option Explicit

Public WithEvents Txt As Access.TextBox

Private Sub Txt_AfterUpdate()
Dim txtName As String, sngval As Single
Dim msg As String

txtName = Txt.Name
sngval = Nz(Txt.Value, 0)

msg = txtName & " _AfterUpdate. :" & sngval
MsgBox msg, vbInformation, Txt.Name

End Sub

Private Sub Txt_LostFocus()
Dim tbx As Variant
tbx = Nz(Txt.Value, "")

If Len(tbx) = 0 Then
  MsgBox Txt.Name & " is Empty.", vbInformation, Txt.Name
End If
End Sub

Moving to the Next Stage

Each TextBox on a Form may accept different types of information, each with its own validation criteria. The data entered in every TextBox must be individually validated to ensure it meets the specified requirements, and appropriate action should be taken if any entry fails to comply.

The code above displays a generalized message for all TextBoxes from the subroutine.  That may not be sufficient for real applications.  We need to write specific Code for each TextBox when the above Event fires from every TextBox.

We will continue this discussion next week for more details on this topic.

Links to WithEvents ...Tutorials.

  1. WithEvents MS-Access Class Module Tutorial
  2. WithEvents and Defining Your Own Events
  3. withevents Button Combo List TextBox Tab
  4. Access Form Control Arrays and Event Capturing
  5. Access Form Control Arrays and Event-2
  6. Access Form Control Arrays and Event-3
  7. WithEvents in Class Module for Sub-Form TextBox Events
  8. WithEvents in Class Module and Data Entry
  9. WithEvents and Access Report Event Sink
  10. WithEvents and Report Lines Hiding
  11. WithEvents and Report Lines Highlighting
  12. Withevents TextBox and Command Button Arrays
  13. Withevents TextBox CommandButton Dictionary
  14. Withevents and all Form Control Types

Share:

Display Records from Dictionary to Form

Employee Records from Dictionary to Form.

We will now perform a similar exercise to what we did earlier with the Collection Object—displaying table records on a form based on a key value selected from a Combo Box.

This time, we will use a Dictionary Object to store Employee Records, using the Last Name as the Key.

Design a sample form:

  • Create a Combo Box in the Header Section (to list all employees' last names).

  • A few TextBox controls in the Detail Section (to display the selected employee’s information).

We will then write the Form-based event procedures in the Form Class Module.

  1. Load data records from a Table or Query into the Dictionary Object.

  2. Retrieve a specific record from the Dictionary, based on the selected key (Last Name) from the Combo Box.

  3. Populate the TextBoxes on the form with the retrieved record values.

Note: You can download a Demo Database, with the Form and VBA Code, from the bottom of this page.

Let us start with the preparation steps so that you will know what it takes to complete this Project.  You will be better informed of the whole process if you plan to implement this method in one of your own projects.

The Employees Table for Sample Data.

We need some data to load into the Dictionary Object.

  1. Import the Employees Table from the Northwind sample database.
  2. Copy and paste the following SQL String into the SQL editing window and save it with the name: EmployeesQ
    SELECT Employees.[Last Name], Employees.[First Name], Employees.[E-mail Address], Employees.[Job Title], Employees.[Business Phone], Employees.[Home Phone]
    FROM Employees;
    

    The Sample Form with a Few Textboxes and a Combo Box.

    We will use only a few fields of data from the Employees table.  We can quickly design a Form with the field names from EmployeesQ, but will not attach the EmployeesQ to the Form as a record source.  The next steps will be needed to add Text Boxes with correct data field names, without typing them into the Name Property of the Text Boxes.

    NB: You can give any name to the Text Boxes; it works with any name.

  3. Select the Design Form option from the Forms Group of the Create Menu.  It will open a Blank Form.

  4. Right-click on the Form and select Form Header/Footer to insert Header and Footer sections into the Form.

    The Sample Design of the Form is given below.

  5. Click on the Detail Section of the Form to make it an active Section.

    Now, we will add six Text Boxes from the Employee record field names as the Text Box Names.

  6. Click on the 'Add Existing Field' Button from the Tools Buttons Group in the Design Menu.
  7. Find the Employees Table and click on the [+] Symbol to show the Employees Table Fields.
  8. Double-click on the following list of Fields, one by one, to insert them into the Detail Section of the Form:
    • Last Name
    • First Name
    • E-mail Address
    • Job Title
    • Business Phone
    • Home Phone

    NB: This is an Unbound Form, and the inserted Field controls also must be Unbound Text Boxes.

    Keep the Text Box's Name Property Value (Field Name) and remove the Control Source Property Value.

  9. Click on the first Text Box to select it.
  10. Display the Property Sheet (F4) of the selected Text Box.
  11. Remove the data Field Name from the Control Source Property to make the text box Unbound.  Ensure that the Name Property Value remains intact.
  12. Remove other Text Boxes Control Source Property Values.

    In the Header Section of the Form, we need the LastName list of Employees in a Combo Box.

  13. Select the Combo-Box control from the Controls Group under the Design Menu and place the Combo-Box control in the Header Section of the Form.  If the Control Wizard is active, then follow steps 14 to 18, and go to step 19 

  14. If the Control Wizard is on, then select the first option and click Next.

  15. Select the Query Option on the next screen, select EmployeeQ, and click Next.

  16. Double-click the Last Name to select and insert it into the right panel, and click Next.

  17. Select the Last Name in the first text box to sort Last Names in Ascending Order, and click Next.

  18. On the next screen, click Finish.

  19. Change the Name Property Value of the Combo-Box to cboLastName.

  20. Find the Limit to List Property of the Combo Box and change the Value to Yes.

  21. Copy and paste the following SQL into the Row Source Property of the Combo-Box:

    SELECT EmployeesQ![Last Name] FROM EmployeesQ;  
  22. Insert a Command Button in the Footer Section of the Form.

  23. Change the Caption of the Command Button to Exit and the Name Property value to cmdClose.

  24. Select the View Code Button from the Tools group to display the Form's Class Module.

  25. Highlight the entire VBA Code below, copy and paste it into the Form’s Class Module, overwriting the existing lines of Code:

    The Form's Class Module VBA Code.

    Option Compare Database
    Option Explicit
    
    Private D As Object
    Dim txtBox() As String
    
    Private Sub Form_Load()
    Dim db As Database
    Dim rst As Recordset
    Dim Rec() As Variant
    Dim fldCount As Long, ctl As Control
    Dim k As Long, frm As Form, Sec As Section
    Dim strKey As String
    
    'Restore the Form to it's actual design size
    DoCmd.Restore
    
    'instantiate Dictionary Object
       Set D = CreateObject("Scripting.Dictionary")
       
    
    'Open Recordset Source to save in Dictionary
       Set db = CurrentDb
       Set rst = db.OpenRecordset("EmployeesQ", dbOpenDynaset)
    'get recordset fields count
       fldCount = rst.Fields.Count - 1
    
    'Redimension Field Names Array (Rec) for number of fields in Table
       ReDim Rec(0 To fldCount) As Variant
    
       'Add records to Dictionary Object
       Do While Not rst.EOF
         'Get current record field values into Rec Variant Array
         For k = 0 To fldCount
            Rec(k) = rst.Fields(k).Value
         Next
         'Last Name as Dictionary Key
         strKey = rst.Fields("[Last Name]").Value
         
        'Add record to Dictionary Object with 'Last Name' Key
         D.Add strKey, Rec
         rst.MoveNext
       Loop
       
       'Set current Form
       Set frm = Me
       
    'Set Detail Section of Form to look for Text Boxes
       Set Sec = frm.Section(acDetail)
       
    'Redim txtBox Array to save Textbox Names on the Form
    'To display field values
       ReDim txtBox(0 To fldCount) As String
      
      'Get Text Box Names,from Detail Section of Form, and save them into Array.
      'this will be used in the ComboBox AfterUpdate Event
      k = 0
      For Each ctl In Sec.Controls
         If TypeName(ctl) = "TextBox" Then
            txtBox(k) = ctl.Name
            k = k + 1
         End If
      Next
       
       rst.Close
       Set rst = Nothing
       Set db = Nothing
    End Sub
    
    
    Private Sub cboLastName_AfterUpdate()
      Dim strD As String, R As Variant
      Dim j As Long
      Dim L As Long
      Dim H As Long
    
    'Get Selected Key from ComboBox
     strD = Me![cboLastName]
      
      'Retrieve the record from Dictionary
      'using KEY and load the field
      'Values into the Variant Array
      R = D(strD)
      L = LBound(R)
      H = UBound(R)
    'Read Field Values from Array and display
    'them into it's corresponding Textbox names on the Form
      For j = L To H
        Me(txtBox(j)) = R(j)
      Next
      Me.Refresh
    
    End Sub
    
    Private Sub cmdClose_Click()
      DoCmd.Close
    End Sub
    
    
    Private Sub Form_Unload(Cancel As Integer)
      'Clear Dictionary Object from Memory
      Set D = Nothing
    End Sub
    
      
  26. Save the Form with the name Dict_Employees or any other name you prefer.

How it All Works Together.

There are four Subroutines in the above Code.

  • Private Sub Form_Load() Event Procedure.
  • Private Sub cboLastName_AfterUpdate()
  • Private Sub cmdClose_Click()
  • Private Sub Form_Unload(Cancel As Integer)

In the Declaration area of the Module, an Object variable D is defined for the Dictionary Object.  The txtbox() array variable is declared for storing the Text Box names from the Form’s Detail Section and will be used for displaying the selected record’s field values.   

The Dictionary Object is created in the Form_Load Event Procedure,

Immediately after instantiating the Dictionary Object, the EmployeesQ Recordset is opened for adding records to the Dictionary Object.  A Select Query is created to select a few fields of the Employees Table.

The Rec() Variant Array is re-dimensioned for the number of fields in the record.  Each field value is added to the Rec Variant Array element, and the whole array is inserted into the dictionary Object as a single Item (a record), with the Last Name field value as a unique Dictionary Key.

In the next stage of the code, the Dict_Employees Form’s Detail Section area is scanned to identify text boxes, and their names are saved into the textbox() array for use in the cboLastName_AfterUpdate() Event Procedure.  The txtbox() Array was declared in the Module Global area.

When the user selects a name from the Combo Box, the Private Sub cboLastName_AfterUpdate() Event Procedure is executed.  The Form's Normal View image is given below:

When the user selects Last Name from the cboLastName Combo Box, it is saved into the String Variable strD. The statement R=D (strD) reads the corresponding employee record field values array into the Variant Variable R. 

We have not explicitly defined the Variant Variable R as an Array. But when we read an Array of values from a Dictionary Object Item into it, it automatically re-dimensions itself with the required number of elements and loads each field value into them.  

The next two steps determine the Array Index range values. 

Within the For ... Next Loop, the record values are displayed in the Form Text Boxes, using the TextBox names saved in the Form_Load() Event Procedure.

You may select other names from the Combo box to display their details on the Form.  When you are ready to close the Form, click on the Exit Command Button.

When the user clicks the Exit Command Button, the Form is closed. Before closing the Form, the Form_Unload Event is triggered, and the Dictionary Object is cleared from Memory.

Download the Demo Database.


Download Dictionary2003.zip


Download Dictionary2007.zip


MS-ACCESS CLASS MODULE

  1. MS-Access Class Module and VBA
  2. MS-Access VBA Class Object Arrays
  3. MS-Access Base Class and Derived Objects
  4. VBA Base Class and Derived Objects-2
  5. Base Class and Derived Object Variants
  6. MS-Access Recordset and Class Module
  7. Access Class Module and Wrapper Classes

    COLLECTION OBJECT

  8. MS-Access and Collection Object Basics
  9. MS-Access Class Module and Collection Object
  10. Table Records in Collection Object and Form

    DICTIONARY OBJECT

  11. Dictionary Object Basics
  12. Dictionary Object Basics-2
  13. Sorting Dictionary Object Keys and Items
  14. Display Records from Dictionary to Form
  15. Add Class Objects as Dictionary Items
  16. Update Class Object Dictionary Item on Form
Share:

Sorting Dictionary Object Keys and Items

Sorting Dictionary Data.

Sorting or indexing table records is a common and important task of organizing data in the correct order, enabling faster retrieval of information through index keys.

In the case of the Dictionary Object, however, there is already a built-in mechanism to directly retrieve information using its unique keys.

Still, if you would like to learn how to sort the values stored in a Dictionary Object, let’s try a simple demonstration. We will reuse the sample data created in earlier example programs as input for our sorting routine. The sample VBA code with the test data is shown below.

The DSort_Test() Main Procedure.

Public Sub DSort_Test()
Dim d As Dictionary
Dim mkey
Dim Title As String
Dim i As Long
Dim vKey() As Variant, vItem() As Variant

Set d = New Dictionary

'Set Key-Text Compare Mode
d.CompareMode = 1 'Text Compare(nancy = NANCY = Nancy = NaNCy)
 
'Syntax: obj.Add "Key", "Content"

'Countries and Capitals
d.Add "Belgium", "Brussels"
d.Add "Italy", "Rome"
d.Add "Canada", "Ottawa"
d.Add "USA", "Washington D.C."
d.Add "Denmark", "Copenhagen"
d.Add "Australia", "Canberra"
d.Add "France", "Paris"
d.Add "Saudi Arabia", "Riyadh"

Title = "UNSORTED LISTING"
GoSub Output_Section

ReDim vKey(1 To d.Count) As Variant
ReDim vItem(1 To d.Count) As Variant

'Load Key,Item pairs into two Variant Arrays
i = 1
For Each mkey In d.Keys
  vKey(i) = mkey
  vItem(i) = d(mkey)
  i = i + 1
Next

'Pass the Array to Bubble Sort Program
Call DBubbleSort(vKey, vItem)

d.RemoveAll 'Remove existing Dictionary Object
Set d = New Dictionary 'instantiate new Dictionary Object

'Re-create Dictionary Object with Sorted Array contents
For i = 1 To UBound(vKey)
   d.Add vKey(i), vItem(i)
Next

Title = "LISTING AFTER SORT"
GoSub Output_Section

Exit Sub

Output_Section:
'Print Sorted Dictionary Object contents
Debug.Print
Debug.Print Title
Debug.Print "---------------------"

For Each mkey In d.Keys
   Debug.Print mkey, d(mkey)
Next
Return

End Sub

In our earlier programs, the Dictionary keys (country names) were manually entered in alphabetical order. However, in this example, we have intentionally mixed up their order. We will pass this unsorted data to a sorting routine and retrieve it back in alphabetical order.

Unfortunately, the Dictionary Object does not provide a built-in way to rearrange its data directly. To sort Dictionary Data, first copy the keys and their corresponding item from the Dictionary into two separate arrays. These arrays can then be passed to a VBA sorting routine to return the data in the desired order.

The Coding Steps.

The Algorithm of the Code segment, after creating the Dictionary Data items in the above program, is given below.

  1. Take the Listing of Unsorted Data from the Dictionary Object.

  2. Define two Array Variables: One for Keys and another for Item Values (if  Items are  Objects, then the second declaration must be for an Object of the Item’s Type).

  3. Read Dictionary Keys and Item Values and load them into separate Arrays.

  4. Pass the Arrays to the Sort Routines as ByRef Parameters.

  5. Remove the existing Dictionary Object and instantiate a new dictionary Object, with the same name.

  6. Read the Sorted Keys and Items from the Array and 'Add' them to the new Dictionary Object in sorted order.

  7. Take the listing of sorted data from the recreated Dictionary Object.

BubbleSort() Routine.

The Bubble-Sort VBA Code is given below:

Public Sub DBubbleSort(varKey() As Variant, varItem() As Variant)
Dim j As Long, k As Long
Dim tmp1 As Variant, tmp2 As Variant

For j = 1 To UBound(varKey) - 1
   For k = j + 1 To UBound(varKey)
      If varKey(k) < varKey(j) Then 'change < to > for Descending Order
      
'save first Key, Item value pairs in temporary variable
          tmp1 = varKey(j)
          tmp2 = varItem(j)

'replace first set of values with second value set
          varKey(j) = varKey(k)
          varItem(j) = varItem(k)
          
'replace second value set with saved values
          varKey(k) = tmp1
          varItem(k) = tmp2
      End If
   Next k
Next j

End Sub

The Unsorted and Sorted listing dumped in the Debug window image is given below:

UNSORTED LISTING
---------------------
Belgium       Brussels
Italy         Rome
Canada        Ottawa
USA           Washington D.C.
Denmark       Copenhagen
Australia     Canberra
France        Paris
Saudi Arabia  Riyadh

LISTING AFTER SORT
---------------------
Australia     Canberra
Belgium       Brussels
Canada        Ottawa
Denmark       Copenhagen
France        Paris
Italy         Rome
Saudi Arabia  Riyadh
USA           Washington D.C.

The Dictionary Keys, with Item Values, are sorted in Ascending Order

Sorting in Reverse Order (Z-A).

With a slight change in the Key comparison statement, we can make the program sort the items in Descending Order.  Replace the Less Than Symbol (<) with the Greater Than Symbol (>) in the DBubbleSort program to sort the items in Descending Order, as shown below.

Existing comparison statement:

If varKey(k) < varKey(j) Then

change to

If varKey(k) > varKey(j) Then

The QuickSort() Sorts The Data Quickly.

If a Dictionary Object contains a large volume of data, Bubble Sort is not suitable, as it takes more time compared to QuickSort.  We have the QuickSort program too for sorting Dictionary Data. 

Sample QuickSort VBA Code is given below:

Public Function DictQSort(DxKey As Variant, DxItem As Variant, lngLow As Long, lngHi As Long)
Dim tmpKey As Variant, tmpItem As Variant, midKey As Variant
Dim t_Low As Long, t_Hi As Long

midKey = DxKey((lngLow + lngHi) \ 2)
t_Low = lngLow
t_Hi = lngHi

While (t_Low <= t_Hi)
   While (DxKey(t_Low) < midKey And t_Low < lngHi)
      t_Low = t_Low + 1
   Wend
  
   While (midKey < DxKey(t_Hi) And t_Hi > lngLow)
      t_Hi = t_Hi - 1
   Wend

   If (t_Low <= t_Hi) Then
      tmpKey = DxKey(t_Low)
      tmpItem = DxItem(t_Low)
      
      DxKey(t_Low) = DxKey(t_Hi)
      DxItem(t_Low) = DxItem(t_Hi)
      
      DxKey(t_Hi) = tmpKey
      DxItem(t_Hi) = tmpItem
      
      t_Low = t_Low + 1
      t_Hi = t_Hi - 1
   End If
   
  If (lngLow < t_Hi) Then DictQSort DxKey, DxItem, lngLow, t_Hi 'recursive call
  If (t_Low < lngHi) Then DictQSort DxKey, DxItem, t_Low, lngHi 'recursive call
Wend
End Function

You may run the DictQSort() Program from the main Program DSort_Test(), by replacing the statement that calls the DBubbleSort() Sub-Routine, with a Call to the DictQSort() Function, as shown below:

Replace:

Call DBubbleSort(vKey, vItem)

with

Call DictQSort(vKey, vItem, LBound(vKey), UBound(vKey))

You may not notice any significant difference in execution time between the two programs with this small dataset. However, when working with a large volume of data, the QuickSort method completes the task in only a fraction of the time taken by the Bubble Sort program.

In these sorting procedures, the Keys and their corresponding Item values are first copied into two separate arrays before being passed to the sorting routine. Once the data is sorted, it is added back into a new Dictionary Object, and the old one is removed.

We can achieve the same result using a simpler approach. We only need to sort the Keys in the desired order—either ascending or descending. Using these sorted Keys, we can retrieve the corresponding Item values from the original Dictionary and add them to a new Dictionary Object in the sorted order. Finally, the old unsorted Dictionary Object can be discarded.

The modified version of the top program, with a built-in Bubble Sort Code, is given below.

Public Sub DSort_Test2()
Dim d As Dictionary
Dim y As Dictionary
Dim mkey, j As Long, k As Long
Dim Title As String
Dim i As Long
Dim vKey() As Variant

Set d = New Dictionary

'Set Key-Text Compare Mode
d.CompareMode = 1 'Text Compare(nancy = NANCY = Nancy = NaNCy)
 
'Syntax: obj.Add "Key", "Content"

'Countries and Capitals
d.Add "Belgium", "Brussels"
d.Add "Italy", "Rome"
d.Add "Canada", "Ottawa"
d.Add "USA", "Washington D.C."
d.Add "Denmark", "Copenhagen"
d.Add "Australia", "Canberra"
d.Add "France", "Paris"
d.Add "Saudi Arabia", "Riyadh"

Title = "UNSORTED LISTING"
'Print Unsorted Dictionary Object contents
Debug.Print
Debug.Print Title
Debug.Print "---------------------"

For Each mkey In d.Keys
   Debug.Print mkey, d(mkey)
Next

ReDim vKey(1 To d.Count) As Variant
'Load Keys into Variant Array
i = 1
For Each mkey In d.Keys
  vKey(i) = mkey
  i = i + 1
Next
'Bubble Sort the Keys in Ascending Order
For j = 1 To UBound(vKey) - 1
   For k = j + 1 To UBound(vKey)
       If vKey(k) < vKey(j) Then 'Ascending Order
          mkey = vKey(j)
            vKey(j) = vKey(k)
          vKey(k) = mkey
       End If
    Next k
Next j
'end of Sort

'create sorted Data in a new Dictionary Object
Set y = New Dictionary
For j = 1 To UBound(vKey)
  y.Add vKey(j), d(vKey(j))
Next

'Delete old unsorted Dictionary Object d
d.RemoveAll

Debug.Print
Title = "LISTING AFTER SORT"
Debug.Print Title
Debug.Print "---------------------"
For Each mkey In y.Keys
   Debug.Print mkey, y(mkey)
Next

End Sub

In this example, the Dictionary Keys are first loaded into the vKey() Variant Array. The Bubble Sort procedure then rearranges the Keys in the desired order.

Using these sorted Keys, the corresponding Item values are retrieved from the original Dictionary Object and written into a new Dictionary Object, maintaining the order of the sorted country names.

In the subsequent printing section, the sorted country names and their capitals are printed in the Debug Window from the new Dictionary Object.

However, do we really need to recreate a new Dictionary Object after sorting the Keys? Not necessarily. Since Dictionary Items can be accessed randomly using dictionary Keys, sort only the Keys and hold them in an Array. You can then use the sorted Keys in sequence to retrieve the Items from the existing Dictionary in the desired order (A–Z or Z–A). I’ll leave this approach as an exercise for you to try on your own.

MS-ACCESS CLASS MODULE

  1. MS-Access Class Module and VBA
  2. MS-Access VBA Class Object Arrays
  3. MS-Access Base Class and Derived Objects
  4. VBA Base Class and Derived Objects-2
  5. Base Class and Derived Object Variants
  6. MS-Access Recordset and Class Module
  7. Access Class Module and Wrapper Classes

    COLLECTION OBJECT

  8. MS-Access and Collection Object Basics
  9. MS-Access Class Module and Collection Object
  10. Table Records in Collection Object and Form

    DICTIONARY OBJECT

  11. Dictionary Object Basics
  12. Dictionary Object Basics-2
  13. Sorting Dictionary Object Keys and Items
  14. Display Records from Dictionary to Form
  15. Add Class Objects as Dictionary Items
  16. Update Class Object Dictionary Item on Form
Share:

Dictionary Object Basics

Introduction to Dictionary Object.

A Dictionary object is a VBA object that stores data as key-item pairs, where each unique key is associated with a corresponding value or object. Unlike a Collection, which is primarily index-based, a Dictionary is designed for fast retrieval of data using unique keys.

The Dictionary object is provided by the Microsoft Scripting Runtime library (Scripting.Dictionary). It is particularly useful and efficient when data must be searched, updated, or verified based on a unique identifier. 

Key Characteristics

  1. Key-item storage – Each entry consists of a unique key and its associated item (value/object).

  2. Fast key lookup – Items are retrieved directly by key without searching sequentially through the collection.

  3. Dynamic size – Entries can be added or removed at runtime.

  4. Unique keys – Duplicate keys are not permitted.

  5. Flexible item types – Items can be simple data types, arrays, or object references.

  6. Modifiable keys – Existing keys can be renamed using the Key property.


By now, I hope you have reviewed the recent articles on using the Collection Object in Microsoft Access. Even if you haven’t, you should still be able to follow along with the Dictionary Object and its usage. Collection and Dictionary Objects share many similarities, but understanding their differences will help you decide which one is best suited for a particular task.

In either case, the links are given below for easy access.  

The Dictionary Object is not natively part of Microsoft Access VBA; it originates from VBScript, commonly used on web pages. To use a Dictionary Object in Access, we need to create it explicitly in a VBA program. There are two ways to accomplish this in Microsoft Access VBA:

A.   With the use of the MS Access function CreateObject().

Dim d As Object

Set d = CreateObject("Scripting.Dictionary")

This approach has a minor drawback for beginners: IntelliSense will not display the Dictionary Object’s methods and properties, because the object is declared as a generic Object type.

Dictionary Object Library File.

B.  But there is a better method. Add the Microsoft Scripting Runtime Library to the selected existing list of Libraries in Microsoft Access.

When we do that, we can declare and use the Dictionary Object as we did for the Collection Object.

  1. Select the References option from the Tools Menu in the VBA Window. 

  2. The sample display of Library Files is given below. 

  3. The check-marked item (Microsoft Scripting Runtime) is the Library File you need to look for in your System.  The unchecked items are in alphabetical order.

  4. Move the Scrollbar down and find the file Microsoft Scripting Runtime, select it, and click the OK Button to exit.

Now, you can declare and instantiate a Dictionary Object with IntelliSense support.

Dim d As Dictionary

Set d = New Dictionary

OR

Dim d As New Dictionary

Dictionary Object has the following List of Methods and Properties:

    Method        Description

    Add        -     Adds an item to the object with the specified Key.  Always adds an Item with a Key-Value.

    Exists      -    Verifies that the specified key exists.

    Items Return - Returns an array of Item (Element) Values.

    Keys    -        Returns an array of Keys.

    Remove -    Removes the Item specified by the Key.

    RemoveAll  -    Removes the Dictionary Object from Memory.


    Property        Description

    Count   -       Gives the count of Items in the dictionary.

    Item     -        Retrieve/Replace/Add the item with the specified key.  If the specified key doesn’t exist, the Item value is added to the Dictionary under the specified key.

    Key     -          Replaces the specified Key with a new Key.

    CompareMode  -    Mode for comparing string keys.

    0  -  Binary (default): A <> a, A<a

    1  -   Text: A=a, Aa=aa, AA=aa

The Test Run Code.

  1. Copy and paste the following sample code into your VBA Standard Module:
    Public Sub Dict_Test0()
    Dim d As Dictionary
    Dim mkey, mitem
    Dim strKey As String
    Dim msg As String
    Dim Title As String
    
    Set d = New Dictionary
    
    'Set Key-Text Compare Mode
    d.CompareMode = 1 'Text Compare(nancy = NANCY = Nancy = NaNCy)
     
    'Syntax: obj.Add "Key", "Content"
    
    'Countries and Capitals
    
    d.Add "Australia", "Canberra"
    d.Add "Belgium", "Brussels"
    d.Add "Canada", "Ottawa"
    d.Add "Denmark", "Copenhagen"
    d.Add "France", "Paris"
    d.Add "Italy", "Rome"
    d.Add "Saudi Arabia", "Riyadh"
    d.Add "USA", "Washington D.C."
    
    For Each mkey In d.Keys
       msg = msg & mkey & vbCr
    Next
    
    msg = msg & vbCr & "Select a Country, Q=Quit."
    Title = "Dict_Test0()"
    strKey = ""
    
    Do While strKey = "" And strKey <> "Q"
       strKey = InputBox(msg, Title, "")
       If strKey = "Q" Then
          Exit Do
       End If
    
    If d.Exists(strKey) Then
    mitem=d(strKey)
        MsgBox "Country: " & UCase(strKey) & vbCr & vbCr & " Capital:  " & UCase(mitem), , Title
    Else
        MsgBox "Country: " & UCase(strKey) & vbCr & vbCr & "Doesn't exists.", , Title
    End If
    
       strKey = ""
    Loop
    
    'Remove Dictionary from memory
    d.RemoveAll
    
    End Sub

    Viewing the Values in Memory.

  2. Insert a Stop statement immediately below the USA, Washington, D.C. Add a statement.

  3. Select the Locals Window option from the View Menu.

  4. Click anywhere in the Code, press F5 to run the Code.

The Program pauses at the Stop statement.

Check the Locals Window, click the plus symbol in [+] d, and view the contents.  It shows only the Key Values, and the Item values are not visible. 

Press the F5 Key again to continue executing the Code.

Enter a Country Name from the displayed list and then press the Enter Key or click the OK Command Button to display the selected Country’s Capital.

You can type the country name in upper-case, lower-case, or in mixed form.  The compare mode setting at the beginning of the code takes care of comparing the Key value entered by you with the list of keys in the Dictionary Object.

Enter the letter Q to Exit from the Do ... Loop and stop the Program.

How it Works.

Let us review the code.  Since I have already added the Microsoft Scripting Runtime File into my selected list of VBA Library files, I could declare the variable d as a Dictionary Object, as we did with the Collection Object. Declared a few other required Variables as well.

The statement Set d = New Dictionary instantiates the Dictionary in memory as Object d.

The d.CompareMode determines how the given Key Value is compared with the existing list of Keys in memory to retrieve, replace Item or Key-Value.

The Syntax Comment line indicates how to add an item to the Dictionary Object as its Element.

In the Dictionary Object, the Key is the first parameter and the Item is the second. Both Key and Item Parameters are mandatory and separated by a Comma. 

In the Collection Object, the order of both these parameters is reversed.  The first Parameter is Item, and the second Parameter, Key, is Optional.

The d.Add the statement, and check whether the given key already exists in the Dictionary Object first; if it does, display an error message:  ‘This key is already associated with an element of this Collection’. The key values must be unique.

If CompareMode=1, then the variants of the name ‘Nancy’, ‘nancy’, ‘NaNcY’ are all referring to the same Key NANCY or nancy. 

If CompareMode=0 (Binary Compare), then all three names are different Keys.

When the Add method finds that the specified Key value doesn’t match any existing Keys, the new Key is added to the Item Value in the Dictionary Object.

The Key Value can be of any Data Type except Variant, Array, or Object.  Stick with one Key value Type for all Items, not a mix of different data types.

We have added eight country names and their capitals. 

The For Each … Next statement reads the list of Keys from the Dictionary Object and prepares a menu for the InputBox () Function. 

The conditional Do While ... Loop runs until the User enters the letter Q or q (Quit) in the InputBox() function.

The user types a Country name through the InputBox() function to display the Country’s capital in a message box. 

The entered country name in the strKey variable is validated using the d.Exists() method to ensure that the entered Key exists in the Dictionary, reads the corresponding Item value, and displays it in the Message Box.

When the user enters the letter Q in the InputBox function, the program stops executing the statement d.RemoveAll That clears the Dictionary Object from memory.

We have read the Key Values alone using the For Each mKeys In d.Keys statement to create a list of Keys for the InputBox Menu.  The d.Keys statement creates a 0-based Array of Key Values.  You can create a separate Array of Key Values with the following statement:

myKeys = d.Keys

Determine the Array elements LBound and UBound values to work with the list.

In the same way, we can read all Items (elements) into an Array, away from the Dictionary Object, to work with it if needed.

Take a Listing of All Items.

Let us create a list of all the Items, with the method explained above.  We will make a copy of the above Code and make some changes to retrieve the Items into an Array and print them into the Debug Window.

Here is the Code:

Public Sub Dict_Test0_1()
Dim d As Dictionary
Dim mitem, j As Long

Set d = New Dictionary

'Set Key-Text Compare Mode
d.CompareMode = 1 'Text Compare(nancy = NANCY = Nancy = NaNCy)
 
'Syntax: obj.Add "Key", "Content"

'Countries and Capitals
d.Add "Australia", "Canberra"
d.Add "Belgium", "Brussels"
d.Add "Canada", "Ottawa"
d.Add "Denmark", "Copenhagen"
d.Add "France", "Paris"
d.Add "Italy", "Rome"
d.Add "Saudi Arabia", "Riyadh"
d.Add "USA", "Washington D.C."

mitem = d.Items

Debug.Print "Country Capitals"
Debug.Print "----------------"
For j = LBound(mitem) To UBound(mitem)
   Debug.Print j, mitem(j)
Next

'Remove the Dictionary from memory
d.RemoveAll

End Sub

Copy and paste the code into a Standard Module. Display the Debug Window (CTRL+G).

Run the code to get a list of Country Capitals in the Debug Window as shown below.

Country Capitals
----------------
 0            Canberra
 1            Brussels
 2            Ottawa
 3            Copenhagen
 4            Paris
 5            Rome
 6            Riyadh
 7            Washington D.C.

You may modify the item = d.Items statement to mitem = d.Keys to take a listing of all Countries.

We will continue this discussion Next Week.

MS-ACCESS CLASS MODULE

  1. MS-Access Class Module and VBA
  2. MS-Access VBA Class Object Arrays
  3. MS-Access Base Class and Derived Objects
  4. VBA Base Class and Derived Objects-2
  5. Base Class and Derived Object Variants
  6. MS-Access Recordset and Class Module
  7. Access Class Module and Wrapper Classes

    COLLECTION OBJECT

  8. MS-Access and Collection Object Basics
  9. MS-Access Class Module and Collection Object
  10. Table Records in Collection Object and Form

    DICTIONARY OBJECT

  11. Dictionary Object Basics
  12. Dictionary Object Basics-2
  13. Sorting Dictionary Object Keys and Items
  14. Display Records from Dictionary to Form
  15. Add Class Objects as Dictionary Items
  16. Update Class Object Dictionary Item on Form
Share:

Table Records in Collection Object and Form

Table Records in Collection Object.

Data records from a table will be added as items in the Collection Object, with the Description field values used as the Key parameter for each item.

The source values for a ComboBox on a Form are also taken from the Table's Description Field. Selecting an item from the ComboBox uses its value as the key to retrieve the corresponding record from the Collection object and display the values in unbound text boxes on the form.

For experimentation, we have created a small table, Table 1, with a few sample records.

The Table image is given below:

The Table Structure image is given below for reference.

The Sample Demo Form.

We have designed a small form with a Combo box in the Form Header.  The Row Source Property of the Combo box is set with the following SQL:

SELECT [Table1].[Desc] FROM Table1 ORDER BY [Desc]; 

To pick the Desc field value as the Row Source of the Combo Box.

Four text boxes with their Child Labels are inserted in the Detail Section of the Form.  The Text Box Name Property values are set with the same name as each field on the Table, for easier reference in the Program, in the same order they appear on the Table.

The image of the frmTable1 design is given below:

The Normal View of the Form frmTable1, with data displayed from the Collection Object, is given below for reference.  The Combo box contents are also shown in the Form.

The following code runs in the frmTable1 Form’s Class Module.  If you have already designed the above Form, ensure that the text boxes are assigned the field name of the Table structure shown above.  The Combo box name is cmbDesc.  You can download a database with the Code from the link given at the end of this Page. 

Form Module Code.

Copy and paste the following Code into the frmTable1’s Class Module:

Option Compare Database Option Explicit Private Coll As Collection Dim txtBox() As String Private Sub Form_Load() Dim db As Database Dim rst As Recordset Dim flds As Long, k As Long

Dim frm As Form, Sec As Section, ctl As Control Dim Rec() As Variant, strKey As String 'Open Table1 to upload records into Collection Object Set db = CurrentDb Set rst = db.OpenRecordset("Table1", dbOpenDynaset) 'get record fields count flds = rst.Fields.Count - 1

'Set Detail Section of Form to scan for Text Boxes Set frm = Me Set Sec = frm.Section(acDetail) 'Redim txtBox() to save Textbox names from Form 'to display field values ReDim txtBox(0 To flds) As String 'Get Text Box Names & save into txtBox() Array from Detail Section of Form 'this will be used in ComboBox AfterUpdate Event Procedure k = 0 For Each ctl In Sec.Controls If TypeName(ctl) = "TextBox" Then txtBox(k) = ctl.Name k = k + 1 End If Next

'instantiate Collection Object Set Coll = New Collection

'Redimension Rec Array for number of fields in Table ReDim Rec(0 To flds) As Variant 'Add each record into the Collection Object Do While Not rst.EOF 'Get current record field values into Rec Variant Array For k = 0 To flds Rec(k) = rst.Fields(k).Value Next

'Description Field Value as Key strKey = rst.Fields("Desc").Value 'Add record to the Collection Object with Key Coll.Add Rec, strKey rst.MoveNext Loop rst.Close Set rst = Nothing Set db = Nothing End Sub

Private Sub cmbDesc_AfterUpdate() Dim strD As String, R As Variant Dim j As Long, L As Long, H As Long 'Get Selected Collection Key from ComboBox strD = Me![cmbDesc] 'Retrieve the record from Collection 'using Collection KEY and save the field 'Values into the Variant Variable R = Coll(strD) L = LBound(R) H = UBound(R) 'Add Field Values into corresponding Text Boxes For j = L To H Me(txtBox(j)) = R(j) Next Me.Refresh End Sub Private Sub Form_Unload(Cancel As Integer) 'Remove Collection from Memory on Form Close Set Coll = Nothing End Sub

This is how it works:

  1. All Records from the Table are added as the Collection Object Items in the Form_Load() Event Procedure.  The record description Field (Desc) value is used as the Key parameter value of the Item method.

  2. The Desc field values are also used as Combo Box List values on the Form.

  3. When the user selects an item from the Combo Box, the cmbDesc_AfterUpdate() event procedure retrieves the record from the Collection Object using the Key value from the combo box, and displays the record field values in the Text Boxes on the Form.

  4. The Objects are cleared from memory when the Form is closed.

In the declaration area of the module, we declare the Collection object Coll and an empty array txtBox().

Within the Form_Load event procedure, the Database object db and Recordset object rst are declared. Next, the variable flds is declared to store the count of record fields.

Form, Section, and Control objects are also declared. These are used to locate text boxes on the form, collect their Name property values, and store them in the txtBox array.

A Variant array Rec() is used to temporarily hold record field values before adding them as a single record item to the Collection object.

The string variable strKey is used to assign the record’s Description, which will serve as the key for the current record in the Collection object. Each key in the Collection must be unique.

Note: The VBA code lines are commented appropriately. Go through the code line by line a second time to fully understand its purpose.

The Form_Load() event procedure does the following:

  1. The procedure opens Table1 and reads the field count of the first record, storing it in the variable flds.

  2. The form’s Detail Section is assigned to the sec object variable.

  3. All TextBox controls within the Detail Section of the form are located, and their Name properties are collected into the txtBox() array.

  4. Next, the Collection object is instantiated as the object variable Coll.

  5. At the start of the Do While…Loop, the field values of the current record are added to the Rec Variant array.

  6. The Description (Desc) field value is saved into the string variable strKey.

  7. The statement Coll.Add Rec, strKey adds the current record’s values from Rec as a new item in the Collection, using strKey as the key.

  8. The statement rst.MoveNext advances the record pointer to the next record, and this process repeats until all records in the table have been added to the Collection.

  9. Finally, the Table1 recordset is closed.

In the Form Load Event Procedure, all the records in the Table are loaded into the Collection Object.  The Combo Box in the Form’s Header Section is populated with the values from the table’s Description field.

When a user selects an item from the Combo Box, the cmbDesc_AfterUpdate() event procedure is triggered.

The selected Combo Box value is stored in the variable strD, which is then used in the statement R = Coll(strD) to retrieve the corresponding record array from the Collection using strD as the Key. Alternatively, R = Coll.Item(strD) works equally well.

Notice that the Variant variable R is not explicitly declared as an array. VBA automatically determines the correct data type and dimensions based on the record retrieved from the Collection.

The next steps in the VBA code calculate the Array lower and upper bounds and use them as control values in a For … Next loop. This loop copies the record field values into the corresponding Text Boxes on the Form, using the Text Box names stored in the txtBox array.


Download the Demo Database.

Download TableColl2003.zip

Download TableColl2007.zip


  1. MS-Access Class Module and VBA
  2. MS-Access VBA Class Object Arrays
  3. MS-Access Base Class and Derived Objects
  4. VBA Base Class and Derived Objects-2
  5. Base Class and Derived Object Variants
  6. MS-Access Recordset and Class Module
  7. Access Class Module and Wrapper Classes
  8. MS-Access and Collection Object Basics
  9. MS-Access Class Module and Collection Object
  10. Table Records in Collection Object and Form
  11. Dictionary Object Basics
  12. Dictionary Object Basics-2
  13. Sorting Dictionary Object Keys and Items
  14. Display Records from Dictionary to Form
  15. Add Class Objects as Dictionary Items
  16. Update Class Object Dictionary Item on Form
Share:

PRESENTATION: ACCESS USER GROUPS (EUROPE)

Translate

PageRank

Post Feed


Search

Popular Posts

Blog Archive

Powered by Blogger.

Labels

Forms Functions How Tos MS-Access Security Reports msaccess forms Animations msaccess animation Utilities msaccess controls Access and Internet MS-Access Scurity MS-Access and Internet External Links Queries Array Class Module msaccess reports Accesstips msaccess tips WithEvents Downloads Objects Menus and Toolbars MsaccessLinks Process Controls Art Work Collection Object Property msaccess How Tos Combo Boxes ListView Control Query VBA msaccessQuery Calculation Dictionary Object Event Graph Charts ImageList Control List Boxes TreeView Control Command Buttons Controls Data Emails and Alerts Form Custom Functions Custom Wizards DOS Commands Data Type Key Object Reference ms-access functions msaccess functions msaccess graphs msaccess reporttricks Command Button Report msaccess menus msaccessprocess security advanced Access Security Add Auto-Number Field Type Form Instances ImageList Item Macros Menus Nodes Recordset Top Values Variables msaccess email progressmeter Access2007 Copy Excel Expression Fields Join Methods Microsoft Numbering System RaiseEvent Records Security Split SubForm Table Tables Time Difference Utility WScript Workgroup Wrapper Classes database function msaccess wizards tutorial Access Emails and Alerts Access Fields Access How Tos Access Mail Merge Access2003 Accounting Year Action Animation Attachment Binary Numbers Bookmarks Budgeting ChDir Color Palette Common Controls Conditional Formatting Data Filtering Database Records Defining Pages Desktop Shortcuts Diagram Disk Dynamic Lookup Error Handler Export External Filter Formatting Groups Hexadecimal Numbers Import Labels List Logo Macro Mail Merge Main Form Memo Message Box Monitoring Octal Numbers Operating System Paste Primary-Key Product Rank Reading Remove Rich Text Sequence SetFocus Summary Tab-Page Union Query User Users Water-Mark Word automatically commands hyperlinks iSeries Date iif ms-access msaccess msaccess alerts pdf files reference restore switch text toolbar updating upload vba code