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

Form Bookmarks And Data Editing-2

Continued from Bookmarks and Data Editing

In the first part of this article, we used saved Bookmarks to revisit previously accessed records, enabling us to review and verify the accuracy of any edited information.

The myBookMarks() options can be enhanced with an additional option— the existing Options: 1 = Save Bookmark, 2 = Retrieve Bookmarks, 3 = Initialize Bookmark List—to display all edited records together in Datasheet View.

However, this approach has certain side effects you should be aware of before implementing new features. Recognizing these potential issues early will help you design effective workaround strategies when necessary. In this section, we’ll explore these challenges using the Order Details table as an example.

In the previous example, we used the Bookmark index number along with the OrderID value to verify that the correct records were being retrieved.

In many cases, a single purchase order may contain many products, meaning that all records associated with that order share the same OrderID. If we use OrderID alone as the criteria of a query, it will return all products associated with that order, regardless of which specific record we visited previously.

This limitation didn’t arise when we relied on Bookmarks, since each record has a unique Bookmark that precisely identifies it. In those earlier cases, the OrderID served as a reference point to verify that the retrieved record is the correct one.

However, our current approach uses the OrderID values saved in the ComboBox list as query criteria to retrieve all edited records at once. This can lead to unwanted duplicates or ambiguous results.

We can rectify this by ensuring that each item in the ComboBox list represents a unique record. If the table already has a unique field (such as a primary key), we can use that instead of the OrderID. Otherwise, we can combine multiple field values to create a unique identifier for each record, and store this composite value in the ComboBox list,  along with the Bookmark index number.

This enhancement will form the basis of the fourth option in the myBookMarks() function.

Unique ID Value(s) as Key.

We will now combine the OrderID and ProductID values and store them together in the ComboBox list. Since the same product code will never appear more than once in a single purchase order, this combination guarantees that each ComboBox entry represents a unique record.

This new approach generates a Query based on the ComboBox Bookmark contents, allowing us to display all edited records from the Order Details table with a single click.

In the fourth option of the myBookMarks() function, we will build an SQL statement using the combined OrderID–ProductID values as query criteria. This SQL string will then replace the SQL of a pre-defined SELECT query, enabling it to retrieve the corresponding records.

To trigger this functionality, we’ll add another CommandButton beside the << Reset button. When the user clicks this button, all the edited records are in Datasheet View.

Before proceeding, let’s write the code segment that implements this specific option. We’ll begin by declaring the required objects and variables in the declaration section of the function.

Dim db as Database, QryDef as Querydef
Dim strSql as String, strSqltmp as String, strCriteria as a String
.
.
.
Select Case ActionCode
.
.
.
Case 1
.
Case 2
.
Case 3
.
Case 4

strSqltmp = "SELECT [Order Details].* "
strSqltmp = strSqltmp & "FROM [Order Details] "
strSqltmp = strSqltmp & "WHERE ((([OrderID]" & "&" & Chr$(34)
strSqltmp = strSqltmp & "-" & Chr$(34) & "&" & "[ProductID]) In ('"

strCriteria = ""
For j = 0 To ArrayIndex -1
   If Len(strCriteria) = 0 Then
   strCriteria = ctrlCombo.Column(1, j)
Else
   strCriteria = strCriteria & "','" & ctrlCombo.Column(1, j)
End If

Next

strCriteria = strCriteria & "')));"

Set db = CurrentDb
Set Qrydef = db.QueryDefs("OrderDetails_Bookmarks")
strSql = strSqltmp & strCriteria
Qrydef.SQL = strSql
db.QueryDefs.Refresh
DoCmd.OpenQuery "OrderDetails_Bookmarks", acViewNormal
End Select 

We begin by defining the static portion of the SQL statement in the variable strSqltmp. Next, we loop through the items in the Combo Box, extracting the values from its second column, which contains the combined OrderID and ProductID separated by a hyphen (-). Inside the 'For… Next' loop, these values are used to build the criteria string in the variable strCriteria.

Once the criteria are fully constructed, we redefine the SQL statement of the OrderDetails_BookMarks query, inserting the newly built criteria before opening the query to display the extracted records.

Remember that Combo Box columns in Access use zero-based indexing. This means that the second column is referenced as Column(1, j), where j is the current row index. The statement

strCriteria = strCriteria & "-,'" & ctrlCombo.Column(1, j) 

therefore retrieves the combined OrderID–ProductID string value from the second column and appends it to the criteria string used for record selection.

Modified VBA Code.

The modified Code of the myBookMarks() Function with the above Option is given below.

  1. You may copy the Code and paste it into the Standard Module, replacing the earlier code, or rename the earlier Function and save this Code separately, with the original name.

    Public Const ArrayRange As Integer = 25
    Dim bookmarklist(1 To ArrayRange) As String, ArrayIndex As Integer
    
    Public Function myBookMarks(ByVal ActionCode As Integer, ByVal cboBoxName As String, Optional ByVal RecordKeyValue) As String
    '-----------------------------------------------------------------
    'Author : a.p.r. pillai
    'Date   : October-2009
    'URL    : www.msaccesstips.com
    'Remarks: All Rights Reserved by www.msaccesstips.com
    '-----------------------------------------------------------------
    'Action Code : 1 - Save Bookmark in Memory
    '            : 2 - Retrieve Bookmark and make the record current
    '            : 3 - Initialize Bookmark List and ComboBox contents
    '            : 4 - Filter Records and display in Datasheet View
    '-----------------------------------------------------------------
    Dim ctrlCombo As ComboBox, actvForm As Form, bkmk As String
    Dim j As Integer, msg As String, bkmkchk As Variant
    Dim strRowSource As String, strRStmp As String, matchflag As Integer
    Dim msgButton As Integer
    
    Dim db As Database, Qrydef As QueryDef
    Dim strSql As String, strSqltmp As String, strCriteria As String
    
    'On Error GoTo myBookMarks_Err
    
    If ActionCode < 1 Or ActionCode > 4 Then
       msg = "Invalid Action Code : " & ActionCode & vbCr & vbCr
       msg = msg & "Valid Values : 1 to 4"
       MsgBox msg, , "myBookMarks"
       Exit Function
    End If
    
    Set actvForm = Screen.ActiveForm
    Set ctrlCombo = actvForm.Controls(cboBoxName)
    Select Case ActionCode
        Case 1
            bkmk = actvForm.Bookmark
            'check for existence of same bookmark in Array
            matchflag = -1
            For j = 1 To ArrayIndex
               matchflag = StrComp(bkmk, bookmarklist(j), vbBinaryCompare)
               If matchflag = 0 Then
                   Exit For
               End If
            Next
            If matchflag = 0 Then
               msg = "Bookmark of " & RecordKeyValue & vbCr & vbCr
               msg = msg  & quot;Already Exists."
               MsgBox msg, , "myBookMarks()"
               Exit Function
            End If
            'Save Bookmark in Array
            ArrayIndex = ArrayIndex + 1
            If ArrayIndex > ArrayRange Then
              ArrayIndex = ArrayRange
              MsgBox "Boookmark List Full.", , "myBookMarks()"
              Exit Function
            End If
            bookmarklist(ArrayIndex) = bkmk
    
            GoSub FormatCombo
    
            ctrlCombo.RowSource = strRowSource
            ctrlCombo.Requery
        Case 2
            'Retrieve saved Bookmark and make the record current
            j = ctrlCombo.Value
            actvForm.Bookmark = bookmarklist(j)
        Case 3
            'Erase all Bookmarks from Array and
            'Delete the Combobox contents
            msg = "Erase Current Bookmark List...?"
            msgButton = vbYesNo + vbDefaultButton2 + vbQuestion
            If MsgBox(msg, msgButton, "myBookMarks()") = vbNo Then
                Exit Function
            End If
            For j = 1 To ArrayRange
               bookmarklist(j) = ""
            Next
            ctrlCombo.Value = Null
            ctrlCombo.RowSource = ""
            ArrayIndex = 0
        Case 4
            strSqltmp = "SELECT [Order Details].* "
            strSqltmp = strSqltmp & "FROM [Order Details] "
            strSqltmp = strSqltmp & "WHERE ((([OrderID]" & "&" & Chr$(34)
            strSqltmp = strSqltmp & "-" & Chr$(34) & "&" & "[ProductID]) In ('"
            strCriteria = ""
            For j = 0 To ArrayIndex - 1
                If Len(strCriteria) = 0 Then
                    strCriteria = ctrlCombo.Column(1, j)
                Else
                    strCriteria = strCriteria & "','" & ctrlCombo.Column(1, j)
                End If
            Next
            strCriteria = strCriteria & "')));"
     
           Set db = CurrentDb
            Set Qrydef = db.QueryDefs("OrderDetails_Bookmarks")
            strSql = strSqltmp & strCriteria
            Qrydef.SQL = strSql
            db.QueryDefs.Refresh
            DoCmd.OpenQuery "OrderDetails_Bookmarks", acViewNormal
    End Select
    
    myBookMarks_Exit:
    Exit Function
    
    FormatCombo:
    'format current Bookmark serial number
    'and OrderID to display in Combo Box
    strRStmp = Chr$(34) & Format(ArrayIndex, "00") & Chr$(34) & ";"
    strRStmp = strRStmp & Chr$(34) & RecordKeyValue & Chr$(34)
    
    'get current combobox contents
    strRowSource = ctrlCombo.RowSource
    
    'Add the current Bookmark serial number
    'and OrderID to the List in Combo Box
    If Len(strRowSource) = 0 Then
         strRowSource = strRStmp
    Else
         strRowSource = strRowSource & ";" & strRStmp
    End If
    Return
    
    myBookMarks_Err:
    MsgBox Err.Description, , "myBookMarks()"
    Resume myBookMarks_Exit
    End Function

  2. A Select Query and some Changes in the Form.

    You can test this new option by making a few minor changes to the Form we created earlier (see the design view image below). To begin, create a CommandButton and a simple SELECT Query that we’ll use to display the bookmarked records.

    First, create a new Query with the following SQL statement and save it under the name OrderDetails_BookMarks:

    SELECT Order Details].*
    FROM Order Details];
    

    Next, open the Order Details Form in Design View and add a new CommandButton next to the existing (<) Button, as shown in the sample Form design below. This new button runs the procedure that retrieves and displays the edited records from the Order Details table in Datasheet View.

  3. Click on the newly added Command Button to select it, and open the Property Sheet by choosing View → Properties from the menu.

    In the Property Sheet:

  • Set the Name property to cmdShow.

  • Set the Caption property to View Records.

  • Next, locate the On Click property. From its drop-down list, select [Event Procedure], and then click the Build (…) button. This will open the Form’s Code Module, where Access automatically inserts the empty procedure skeleton, as shown below:

    Private Sub cmdShow_Click()
    
    End Sub
    
  • Write the middle of the Sub-Routine as shown below:

    Private Sub cmdShow_Click()
        myBookMarks 4, "cboBMList"
    End Sub
    

Perform a Trial Run

  1. Save and close the Order Details Form and open it in Normal View.

  2. Double-click on the Record Selector of a few records on the Form to add the Bookmark List to the ComboBox.

  3. Click on the drop-down control of the ComboBox to ensure that the selected Item Codes are added to the ComboBox List.

  4. Click on the View Records CommandButton to open the Query OrderDetails_Bookmarks in Datasheet View with the records that match the ComboBox Values.

  5. Examine the sample image displaying the Query result overlapping the Form, with all records corresponding to the values stored in the Combo Box list.

    Notice that the Product field displays the Product Description instead of the Product Code that appears in the Bookmark Combo Box on the main form. This is because the Display Width of the Combo Box’s first column (Product Code) is set to 0", effectively hiding it from view in Datasheet mode. However, when you select an item from this Combo Box, the Product Code—not the description—is stored in the Order Details table, since it is the bound column.

    When you double-click a record selector, the stored ProductID value (rather than the displayed description) is retrieved and combined with the OrderID value to update the Combo Box list correctly.

    Let us find out how to open a Form with the last record you were working on in an earlier session: Click here.

    Want to find out how to use Combo Boxes and List Boxes in different ways? Visit the following Links:

    1. Selected ListBox Items and Dynamic Query
    2. Create a List from another ListBox
    3. ListBox and Date: Part-1
    4. ListBox and Date: Part-2
    5. ComboBox Column Values
    6. External Files List in Hyperlinks
    7. Refresh Dependent ComboBox Contents
Share:

Form Bookmarks and Data Editing

Form Bookmarks and Data Editing.

Assume you are about to edit information on 25 records in the Form, selected at random by searching for their ID keys. To begin, open the main Data Form and use the Find control (Ctrl+F) to search for each record by entering its key value (for example, Employee Code or OrderID). When the record is current, make the necessary changes. You’ll need to repeat this process for all 25 records the first time, as this is the only way to locate and modify them.

However, since the information you’ve changed is critical, even a small mistake could cause serious issues. Errors can easily slip in when making changes hastily in response to the urgency. Therefore, you need to recheck each record to verify that all changes are accurate.

Unfortunately, repeating the same search-and-edit process for all 25 records—opening the Find dialog, typing the key values, and clicking Find Next each time—is far less appealing the second time around.

But what if you could revisit all those records—one by one, in the exact order you edited them—without repeating the entire cumbersome search process? That would certainly make the verification task much faster and easier.

I emphasized the term in the same order because you’ll likely have your source document or change log arranged in the sequence you first edited the records.

To make this possible, we’ll develop a simple yet powerful technique using the Form’s Bookmarks feature. This method will help application users navigate and review their edited records effortlessly.

FORM BOOKMARKS.

When you open a Form that’s linked to a Table, Query, or SQL statement, each record on that Form is automatically assigned a unique identifying tag by MS Access, known as a Bookmark (a two-byte string value). This happens every time you open a Form having data sources mentioned above. However, Bookmarks are valid only during the current Form session — they are not stored permanently in Tables.

You can read the Bookmark of any record from the Form’s Bookmark property when that record is current, and store it in memory variables. Saved Bookmarks help to quickly return to any record you previously visited.

To make this process easy to use, I’ve created a function called myBookMarks(). With just a ComboBox, a CommandButton, and four lines of VBA code in the Form’s code module, you can implement this powerful navigation method on any Form that has an attached Recordset.

You’re sure to earn a pat on the back from your MS Access application’s users for adding this simple yet powerful feature. Let’s get started with our sample project.

SAMPLE PROJECT.

  1. Open your VBA Editing Window (Alt+F11).

  2. Create a new Standard Module (Insert -> Module), copy and paste the following Code of myBookMarks() Function into the Module, and save it:

    Option Compare Database
    Option Explicit
    
    Public Const ArrayRange As Integer = 25
    Dim bookmarklist(1 To ArrayRange) As String, ArrayIndex As Integer
    
    Public Function myBookMarks(ByVal ActionCode As Integer, ByVal cboBoxName As String, Optional ByVal RecordKeyValue) As String
    '-----------------------------------------------------------------
    'Author : a.p.r. pillai
    'Date   : October-2009
    'URL    : www.msaccesstips.com
    'Remarks: All Rights Reserved by www.msaccesstips.com
    '-----------------------------------------------------------------
    'Action Code : 1 - Save Bookmark in Memory
    '            : 2 - Retrieve Bookmark and make the record current
    '            : 3 - Initialize Bookmark List and ComboBox contents
    '-----------------------------------------------------------------
    Dim ctrlCombo As ComboBox, actvForm As Form, bkmk As String
    Dim j As Integer, msg As String, bkmkchk As Variant
    Dim strRowSource As String, strRStmp As String, matchflag As Integer
    Dim msgButton As Integer
    
    On Error GoTo myBookMarks_Err
    
    If ActionCode < 1 Or ActionCode > 3 Then
       msg = "Invalid Action Code : " & ActionCode & vbCr & vbCr
       msg = msg & "Valid Values : 1,2 or 3"
       MsgBox msg, , "myBookMarks()"
       Exit Function
    End If
    
    Set actvForm = Screen.ActiveForm
    Set ctrlCombo = actvForm.Controls(cboBoxName)
    Select Case ActionCode
        Case 1
            bkmk = actvForm.Bookmark
            'check for existence of same bookmark in Array
            matchflag = -1
            For j = 1 To ArrayIndex
               matchflag = StrComp(bkmk, bookmarklist(j), vbBinaryCompare)
               If matchflag = 0 Then
                   Exit For
               End If
            Next
            If matchflag = 0 Then
               msg = "Bookmark of " & RecordKeyValue & vbCr & vbCr
               msg = msg & "Already Exists. "
               MsgBox msg, , "myBookMarks()"
               Exit Function
            End If
            'Save Bookmark in Array
            ArrayIndex = ArrayIndex + 1
            If ArrayIndex > ArrayRange Then
              ArrayIndex = ArrayRange
              MsgBox "Boookmark List Full. ", , "myBookMarks()"
              Exit Function
            End If
            bookmarklist(ArrayIndex) = bkmk
    
            GoSub FormatCombo
    
            ctrlCombo.RowSource = strRowSource
            ctrlCombo.Requery
        Case 2
            'Retrieve saved Bookmark and make the record current
            j = ctrlCombo.Value
            actvForm.Bookmark = bookmarklist(j)
        Case 3
            'Erase all Bookmarks from Array and
            'Delete the Combobox contents
            msg = "Erase Current Bookmark List...? "
            msgButton = vbYesNo + vbDefaultButton2 + vbQuestion
            If MsgBox(msg, msgButton, "myBookMarks()") = vbNo Then
                Exit Function
            End If
            For j = 1 To ArrayRange
               bookmarklist(j) = ""
            Next
            ctrlCombo.Value = Null
            ctrlCombo.RowSource = ""
            ArrayIndex = 0
    End Select
    
    myBookMarks_Exit:
    Exit Function
    
    FormatCombo:
    'format current Bookmark serial number
    'and OrderID to display in Combo Box
    strRStmp = Chr$(34) & Format(ArrayIndex, "00") & Chr$(34) & ";"
    strRStmp = strRStmp & Chr$(34) & RecordKeyValue & Chr$(34)
    
    'get current combobox contents
    strRowSource = ctrlCombo.RowSource
    
    'Add the current Bookmark serial number
    'and OrderID to the List in Combo Box
    If Len(strRowSource) = 0 Then
         strRowSource = strRStmp
    Else
         strRowSource = strRowSource & ";" & strRStmp
    End If
    Return
    
    myBookMarks_Err:
    MsgBox Err.Description, , "myBookMarks()"
    Resume myBookMarks_Exit
    End Function
  3. Import the following Tables from C:\Program Files\Microsoft Office\Office11\Samples\Northwind.mdb sample Database:

    • Order Details
    • Products

    Note: We are not using the second table directly; the Order Details table references the Products table to display the product descriptions.

    Demo Form Design

    • Click on the Order Details table to select it.

    • From the Insert menu, choose Form, then select AutoForm: Tabular from the list.

    • MS Access will automatically create a tabular form.

    • Save the Form named Order Details.

    A sample image of a Tabular Form in Design View is given below.

  4. Adding a Combo Box and Command Button.

    1. Open the Order Details Form in Design View.

    2. Expand the Form Header area and move the field headings down slightly to make room for a Combo Box and a Command Button, as shown in the sample design above.

    3. If the Toolbox is not visible, open it by selecting View → Toolbox.

    4. If the Control Wizards button on the Toolbox is currently selected, click it again to turn it off.

    5. Select the Combo Box tool from the Toolbox, then draw a ComboBox in the Header Section of the Form, following the layout shown earlier.

    6. With the Combo Box still selected, open its Property Sheet by choosing View → Properties.

  5. Change the following Property Values as shown below:

    • Name = cboBMList
    • Row Source Type = Value List
    • Column Count = 2
    • Column Widths = .5";1"
    • Bound Column = 1
    • List Rows = 8
    • List Width = 1.5"
  6. Change the Caption of the Child Label attached to the ComboBox to Bookmark List.

  7. Create a Command Button on the right side of the Combo Box.

  8. Display the Property Sheet of the Command Button.

  9. Change the following Property Values as shown below:

    • Name = cmdReset
    • Caption = << Reset.

    Form Class Module VBA Code.

  10. Display the Code Module of the Form (View -> Code).

  11. Copy and Paste the following VBA Code into the Module; Save and Close the Form:

    Option Compare Database
    
    Private Sub Form_DblClick(Cancel As Integer)
        'Save Current Record's Bookmark in memory
        myBookMarks 1, "cboBMList", Me![OrderID]
    End Sub
    
    Private Sub cboBMList_Click()
        'Retrieve the bookmark using the
        'index number from the Combobox List
        'and make the respective record current
        myBookMarks 2, "cboBMList"
    End Sub
    
    Private Sub cmdReset_Click()
        'Initialize Bookmarks and Combobox contents
        myBookMarks 3, "cboBMList"
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)    
    'Remove all Bookmarks from Memory
        myBookMarks 3, "cboBMList"
    End Sub

    Perform a Trial Run.

  12. Open the Order Details Form in Normal View.

  13. Double-click on one of the record selectors on the left side of the Form.

  14. Click on the ComboBox Drop-down control to check whether the OrderID value of the Record that you have double-clicked is added to the ComboBox List with a sequence number in the first column or not.

  15. Make a few more double-clicks on different Record selectors up or down in the Form.

  16. Inspect the ComboBox entries once again to ensure that all record references have been added correctly, each with a running serial number.

    Now, let’s test whether we can quickly navigate back to any of these previously visited records by selecting their reference from the saved Bookmarks List displayed in the Combo Box.

  17. Click on the drop-down control of the Combo Box to display the list of Bookmarks and click on one of the items from the list.

    The record corresponding to the selected Order ID will become the current record on the Form. Even if multiple records share the same OrderID, this method will correctly navigate to the exact record you visited earlier because it uses the Bookmark, not a search based solely on the OrderID value. If you relied only on the OrderID, the Form would stop at the first matching record instead of the specific one you previously accessed.

    Try it out by selecting other items from the Combo Box list. This method also works in Forms using a Columnar layout. 


    Important Points to Note.

    I would like to remind you that the list of Bookmarks is saved in the BookMarkList array within the myBookMarks() function in the Standard Module. The ComboBox items are populated from this array. We have dimensioned the array to hold 25 elements, though not all elements may be filled. The filled Array Bookmarks index numbers are stored in the ComboBox first Column.

    Check the following declarations of the Function in the Global area of the Module:

    Public Const ArrayRange As Integer = 25
    Dim bookmarklist(1 To ArrayRange) As String, ArrayIndex As Integer

    You can adjust the index range 25 to a higher or lower number to your specific needs. Alternatively, you can redimension the BookMarkList() array dynamically using the ReDim Preserve statement to increase its size while keeping the existing values intact.

    Let us continue by adding a few more distant record bookmarks to the existing list.

  18. Scroll down the vertical scrollbar of the Form and double-click on the Record-Selectors for a few more records from the distant area of the Recordset.

  19. Now, try to locate any record of these Bookmarks we have added to the list by selecting them one by one from the Combo Box List.

    Isn't it very easy to revisit all those records a second time?

  20. If you want to erase all those Bookmarks from the BookmarkList Array in memory, click on the << Reset CommandButton. After this, you can create a fresh list of Bookmarks.

The OrderID Field Value added to the Combo Box, along with the Bookmark Array Index Number, can be used to cross-check with the retrieved record value to ensure correctness.

Review of VBA Code.

Let us review the Subroutines copied into the Form Module and check what they do.

Private Sub Form_DblClick(Cancel As Integer)

    myBookMarks 1, "cboBMList", Me![OrderID]

End Sub

When you double-click the Record Selector of a record, the above Sub-Routine calls the main function myBookMarks() with the following parameters:

  1. Action Code: 1 – indicates that the current Bookmark (a two-byte string containing displayable and non-displayable characters) should be fetched from the active Form and saved in memory in the BookMarkList array. The array index is incremented using the variable ArrayIndex. This Action Code is evaluated in the Select Case ... End Select block of the myBookMarks() function. Note that the Bookmark value itself is not displayed anywhere.

  2. Combo Box Name: "cboBMList" – This combo Box displays the index number of the BookMarkList array. Providing the control’s name is sufficient to reference it on the active Form.

  3. Record Field Value: OrderID – Displays the record field value in the Combo Box alongside the BookmarkList array index. You can use any field from your table, as long as it helps verify that the correct record is found.

The third parameter of the myBookMarks() function is optional and is omitted when calling the function to retrieve a Bookmark or to clear the Bookmark list, as shown in the following three SubRoutines.

Private Sub cboBMList_Click()
myBookMarks 2, "cboBMList"

End Sub

Private Sub cmdReset_Click()
  myBookMarks 3, "cboBMList"

End Sub

' Erases the Bookmarks when the Form is closed

Private Sub Form_Unload(Cancel As Integer)

  'Remove all Bookmarks from Memory

  myBookMarks 3, "cboBMList"

  End Sub

NB: Since the main Function myBookMarks() references the Active Form, you can implement this method on any Form without directly passing any Form Name to the Function.

  1. Saving, retrieving, and using Bookmarks for finding records is valid only for the current Form session.

  2. Re-querying the Form's contents (not refreshing) recreates the Recordset Bookmarks in the Form; saved Bookmarks are not valid. You must create a fresh Bookmark List to use correctly.

  3. This method will not work on Forms attached to external Data Sources, linked to Microsoft Access, which doesn't support bookmarks.

Share:

Run Slide Show when Form is Idle

Run Slide Show in Idle Form.

This week, we’ll create an image slideshow that runs on the Form when the Form remains idle for a specified period.

Here’s how it works:

When the Main Switchboard Form remains idle for one minute, the slideshow begins with a series of images at fixed intervals—typically every six seconds. The idle and interval durations are customizable to suit your needs.

The Form’s idle time is determined by monitoring user activity. If no interaction occurs (that is, the current control on the Form remains inactive for more than 1 minute), the slide show starts automatically.

Once the user interacts with the Form—by clicking a command button, list box, or any control other than the active one—the Form exits its idle state, and the slide show stops. The system then resets its idle-time counter and resumes monitoring of inactivity from that point onward.

If another Form is overlapping the Main Switchboard, the slide show pauses automatically and resumes only when the Switchboard becomes active again.

To set up the slide show, you’ll need several bitmap images (landscapes, photos, etc.). You can use as many as you like, but all must follow a consistent naming pattern, such as:

1.bmp, 2.bmp, 3.bmp, and so on.

Other image formats, such as JPG, GIF, or PNG, are also supported, though you may briefly see a progress bar as each image loads into the Image control. For best results, ensure that all images are of the same type and dimensions.

Sample Main Switchboard Form.

A sample Main Switchboard Form with the active Slide Show is given below:


The Design Task

  1. To try this trick, first, organize a few bitmap images in a folder as explained above.

  2. Create a copy of your existing Main Switchboard Form (Control Screen).

  3. Open the Form in Design View.

  4. Make enough room on the Form to create an Image Control.

  5. Display the Toolbox (View ->Toolbox) if it is not visible.

  6. Select the Control Wizards button on the Toolbox.

  7. Select the Image Control tool from the Toolbox and draw an Image Control on the Form where you want the SlideShow to appear.

  8. The Common Dialog Control will display. Browse to the Image location and select the image with Serial Number 1 (Image1.bmp).

    The selected image will appear in the Image Control.

  9. While the Image Control is still in the selected state, display the Property Sheet (View -> Properties) and change the following Property Values as indicated below:

    • Name = ImageFrame

    • Size Mode = Zoom

    Note: Before proceeding, we’ll need part of the Picture property value — specifically, the file path where your images are stored. The Image location address is used in the VBA code we’re about to add to the Form’s module.

    Open the Form in Design View, select the Image Control, and check its Picture property in the Property Sheet. Note down the image file location (for example, C:\MyDatabase\Images\1.bmp), or copy and paste it into a Notepad document for future reference.

  10. Display the Code Module of the Form (View -> Code).

  11. Press Ctrl+A to highlight the existing VBA Code in the Module, if present, and press Delete to remove it.

  12. Copy and Paste the following Code into the Form Module.

    Switchboard Form Module VBA Code (Revised Code)

    Option Compare Database
    
    Dim actForm As String, actControl As String, idletime As Integer
    Dim oldForm As String, oldControl As String, imageNo As Integer
    Dim s_path As String
    
    Private Sub Form_Activate()
        Me.TimerInterval = 1000
    End Sub
    
    Private Sub Form_Deactivate()
        Me.TimerInterval = 0
        Me.ImageFrame.Visible = False
    End Sub
    
    Private Sub Form_Load()
    DoCmd.Restore
    idletime = 0
    imageNo = 0
    s_path = CurrentProject.Path
    Me.ImageFrame.Visible = False
    Me.TimerInterval = 1000
    End Sub
    
    Private Sub Form_Timer()
    Dim txt As String
    
    txt = "Slide-Show Starts In: "
    
    actForm = Screen.ActiveForm.Name
    actControl = Screen.ActiveForm.ActiveControl.Name
    
    If actForm = oldForm And actControl = oldControl And actForm = "SlideShow" Then
        idletime = idletime + 1
        
        If idletime > 15 And idletime < 31 Then
            
          Me.Lblup.Visible = True
          Me.Lblup.caption = txt & (30 - idletime) & " Seconds."
            
        Else
            Me.Lblup.Visible = False
        End If
    Else
        oldForm = actForm
        oldControl = actControl
        idletime = 0
        Me.ImageFrame.Visible = False
        Me.Employees.Visible = False
        DoEvents
    End If
    
    If idletime > 30 Then
        Me.Lblup.Visible = False
        DoEvents
       If idletime Mod 5 = 1 Then
            Me.ImageFrame.Visible = True
            Me.Employees.Visible = True
            imageNo = imageNo + 1
            imageNo = IIf(imageNo < 1 Or imageNo > 9, 1, imageNo)
            Me.ImageFrame.Picture = s_path & "\" & imageNo & ".bmp"
            
            DoEvents
       End If
    End If
    
    End Sub
    
    

    Make Important Changes to References

  13. Change the "SlideShow" reference in the VBA code line with your own Main Switchboard Form Name.

  14. Change Number 9, in the second line with bold letters, to match the number of Images you have saved for the Slide Show as explained above.

  15. If your pictures are not Bitmap Images, then change the file extension ".bmp" to indicate your image type.

  16. Save and Close the Form.

  17. Open the Main Switchboard Form in Normal View.

  18. Wait for one minute to begin the Slide Show.

Interrupting the Slide Show.

When the Slideshow is in progress, selecting a control other than the active control on the Form stops the Slideshow, and the image disappears from the Form.

If you don't click any other control on the Form and more than 30 seconds have elapsed since your last click/selection of a control, the Slide Show will run again.

Want to increase or decrease the Form's idle Time? Change the value in the VBA line If idle time > 30 then set an appropriate time value you prefer.

Each Image stays displayed for about 6 seconds. If you want to increase or decrease the display time, then change the Value in the VBA line

When the idle time Mod 5 = 1, change it to the required delay time between two slides for viewing.

Download the Demo Database from the Link given below:

Note: Unzip the Database with Photos into a temporary Folder and open the Database from there. Read the Notes in the Form for details on how it runs and how to disable it, etc.

Share:

Filter Function Output In Listbox-2

Filter Function Output in ListBox-2.

Last week, we explored the Filter() function; a simple example demonstrates how it works. In that example, we assigned constant values directly to the source array elements to keep the VBA code straightforward and easy to follow.

Just as we can filter data on Forms by setting criteria in the Filter property, or use conditions in Queries to extract information from Tables, the Filter() function provides yet another powerful way to process data — but this time, directly from an Array.

By loading data from a Table or Query into an array, we can use the Filter() function to quickly generate results that match (or exclude) a specified pattern.

To understand this better, let’s try an example using the Employees table from the Northwind.mdb sample database. We’ll create a simple Address Book application that uses the Filter() function to find and display matching names or addresses in a List Box based on user input.

The following section outlines the User Interface (UI) design we plan to create and explains how users will interact with it to display information quickly on the Form.

For this experiment, we will design a Form containing the following controls:

  • A List Box to display the filtered results.

  • A Text Box for entering the search text.

  • A Check Box to toggle between matching and non-matching results.

  • A Command Button to execute the filter operation.

An image of the Form in Design View is shown below:

When the Form opens in Normal View, both the ListBox and TextBox controls will be empty.

  • To display all records, the User can type ALL in the TextBox and click the CommandButton. This action will display the names and addresses of all employees in the ListBox.

  • Alternatively, the user can enter a word or phrase — such as part of a name or address — and click the CommandButton to display only those records where the entered text appears anywhere within the name or address fields.

If the Matching Cases Check Box is selected, the filter will include only records that match the search text.
If it is not selected, the filter will instead display all records that do not match the entered text.

To provide the user with the functionality described above, we need two Subroutines in the Form’s Code Module and a User-Defined Function in a Standard Module that utilizes the Filter() function.

  1. Form_Load Event:
    When the Form opens, the first Subroutine runs from the Form_Load() event. It reads data — specifically the First Name, Last Name, and Address fields — from the Employees table. These Field values are joined into a single text string per record and stored in a single-dimensional array variable in memory. This array remains active for as long as the Form is open.

  2. Command Button Click Event:
    The second Subroutine runs when the user clicks the CommandButton. It uses the Filter() function to extract matching entries from the source array based on the search text entered in the TextBox control.

    The Filter() function returns all array elements that match (or, optionally, do not match) the specified search text and saves them into a target array variable (xTarget). The resulting data is then formatted and assigned to the ListBox Row Source property, which displays the filtered results to the user.


The Address Book Project.

Let us prepare the Address Book's Quick Find Project.

The Design Task.

  1. Import the Employees Table from the C:\Program Files\Microsoft Office\Office11\Samples\Northwind.mdb sample database.

  2. Open a new Form in Design View.

  3. Select the List Box Control from the Toolbox and draw a List Box as shown in the design above.

  4. While the List Box is in the selected state, display the Property Sheet (View -> Properties) and change the following Property Values as given below:

    • Name = AddBook
    • Row Source Type = Value List
    • Width = 4.5"
    • Height = 1.75"
    • Font Name = Courier New
    • Font Size = 10
  5. Position the Child Label attached to the List Box above and change the Caption value to Address Book.

  6. Draw a TextBox below the ListBox. Change the Name Property value of the TextBox to xFind. Position the Child Label above the TextBox and change the Caption value to Search Text/ALL.

  7. Create a Check-Box Control to the right of the Text Box. Change the CheckBox Name Property to MatchFlag. Change the Default Value Property to True. Change the Caption value of the child label of Matching Cases.

  8. Create a Command Button to the right of the Check-Box control. Change the Name Property Value of the Command Button to cmdFilter and the Caption Property Value to Filter.

    NB: Ensure that the Name Property Values of the above controls are the same as given above. This is important because we are referencing these names in Programs.

  9. Display the Code Module of the Form (View ->Code).

  10. Copy and paste the following Code into the Form Module:

    The VBA Code

    Option Compare Database
    Option Explicit
    Dim xSource() As Variant
    
    Private Sub Form_Load()
    Dim db As Database, rst As Recordset, J As Integer
    Dim FName As String * 12, LName As String * 12, Add As String * 20
    
    'Take the count of records
    J = DCount("*", "Employees")
    
    'redimension the array for number of records
    ReDim xSource(J) As Variant
    
    Set db = CurrentDb
    Set rst = db.OpenRecordset("Employees", dbOpenDynaset)
    'load the name and addresses into the array
    J = 0
    Do Until rst.EOF
       FName = rst![FirstName]
       LName = rst![LastName]
       Add = rst![Address]
      xSource(J) = FName & LName & Add
    rst.MoveNext
    J = J + 1
    Loop
    rst.Close
    Set rst = Nothing
    Set db = Nothing
    End Sub
    
    Private Sub cmdFilter_Click()
    Dim x_Find As String, xlist As String, xTarget As Variant
    Dim x_MatchFlag As Boolean, J As Integer
    
    Me.Refresh
    x_Find = Nz(Me![xFind], "")
    x_MatchFlag = Nz(Me![MatchFlag], 0)
    
    'if no search criteria then exit
    If Len(x_Find) = 0 Then
      Exit Sub
    End If
        'initialize list box
        xlist = ""
        Me.AddBook.RowSource = xlist
        Me.AddBook.Requery
    
    If UCase(x_Find) = "ALL" Then
        'Take all values from the Source Array
        'Format it as listbox items
        For J = 0 To UBound(xSource())
          xlist = xlist & xSource(J) & ";"
        Next
    Else    'Call the Filter Function
        xTarget = GetFiltered(xSource(), x_Find, x_MatchFlag)
        'format the returned values as list box items
        If Len(xTarget(0)) > 0 Then
            For J = 0 To UBound(xTarget)
                xlist = xlist & xTarget(J) & ";"
            Next
        End If
    End If
        'remove the semicolon from
        'the end of the list box Value List
        If Len(xlist) > 0 Then
            xlist = Left(xlist, Len(xlist) - 1)
        End If
        'insert the list item string
        'and refresh the list box
        Me.AddBook.RowSource = xlist
        Me.AddBook.Requery
    
    End Sub
  11. Save the Form with the name Filter Form.

  12. Copy and paste the following Function into a Standard Module and save the Module:
    Public Function GetFiltered(ByRef SourceArray() As Variant, ByVal xFilterText As Variant, ByVal FilterType As Boolean) As Variant
        GetFiltered = Filter(SourceArray, xFilterText, FilterType)
    End Function
    

    Filter() Function and Filter Property of the Form.

    We cannot use the Filter() Function in the Form Module because the function name clashes with the Form Property Filter.

    We have placed the Filter() function inside a User-Defined Function named GetFiltered() within a Standard Module, along with the required parameters. This allows us to call it easily from the Form’s Module. The first function parameter is passed 'By Reference', enabling direct access to the source array values without creating a separate copy — improving both performance and efficiency.

    The Demo Runs.

  13. Open the Filter Form in Normal View.

  14. Enter the word ALL (in this case, the Matching Cases flag has no effect) in the Text Box control and click on the Filter Command Button.

    This action will display the names and Addresses of all Employees from the xSource() Array loaded from the Employees Table.

  15. Enter the text Ave in the Text Box and ensure that the 'matching cases' check box is in the selected state.

  16. Click on the Command Button.

    This time, the employees' (Nancy & Laura) Names and Addresses are filtered, and the word Ave is in their Address Lines.

  17. Clear the check mark from the 'matching-cases' CheckBox, then click the Filter command button again.

Now, all items except those records having the word Ave will appear in the List Box.

If you review the code we added to the Form Module, you’ll notice that the xSource() array variable is declared in the global section of the module. This way, the data can be accessed and reused across both Subroutines within the Form Module.

In the Form_Load() Event Procedure, we declared three Variables as fixed-length String Type (see the declaration line given below).

Dim FName As String * 12, LName As String * 12, Add As String * 20

When employee names and addresses are read into these variables, the data is left-justified, with the unused portion of each field padded with spaces on the right. This approach maintains a consistent spacing between items and ensures proper alignment when they are displayed.

It’s important to use a fixed-width font, such as Courier New, for the List Box display. This ensures that all text lines are properly aligned and easy to read. We’ve already configured this setting in Step 4 above.

If you click the Filter CommandButton when the TextBox is empty, then the program terminates; otherwise, it calls the GetFiltered() Function and passes the parameter values.

The output Values are returned in the xTarget Array, and the next steps format the Value List and display it in the List Box.

Share:

Filter Function output in ListBox

Filter function output in ListBox.

This FILTER is not related to a Query, SQL WHERE clause, or a Form’s Filter property. It is a powerful built-in VBA function that can filter data from an array based on text matching.

We can use it to search across multiple data fields of a Table, extract either matching or non-matching items, and display the results neatly in a List Box.

The Demo Run of the Filter.

But first, will experiment with a simple example to understand its usage. Copy and paste the sample VBA code given below into a Standard Module in your database:

Public Function myFilter()
Dim X(7) As Variant, Y As Variant
Dim J as Integer, msg as String

X(0) = "Strawberry Milk"
X(1) = "Chocolates"
X(2) = "Milkshake"
X(3) = "Mango Juice"
X(4) = "Icecold Milk"
X(5) = "Apple Juice"
X(6) = "Buttermilk"
X(7) = "Vanilla Icecream"

'Extract all items containing the text "milk" from Array X()
'and save the output in Array Y()
Y = FILTER(x, "milk", True, vbTextCompare)
msg = ""
For J = 0 To UBound(Y)
   msg = msg & J + 1 & ". " & Y(J) & vbCr
Next

MsgBox msg

End Function

Click anywhere within the Code and press F5 to run the Code. The function output will be displayed in a MsgBox.


How It Works

Let us examine the above code closely. Variable X is dimensioned for eight elements, and the Array is loaded with text values.

The FILTER() Function in the statement Y = FILTER(X, "milk", True, vbTextCompare) extracts the items that match the search text milk from the Source Array Variable X and saves the output as an array of Values into Variable Y.

The FILTER() Function accepts four parameters.

The first parameter X is the Array containing the Text Values.

The second parameter  milk is the search text. It is compared against each item in the source array X. Whenever a match is found anywhere within an array element, that item is extracted and added as an element in the target array  Y .

The third True parameter extracts the matched items and saves them in Variable Y. When this value is set to False, the output will be items that do not contain the search text milk.

The fourth parameter dictates the specific comparison method: Binary, Database, or Text Comparison. Here, we have used the Text Comparison method. The third and fourth parameters are Optional.

Try the above Code with different search text: juice or Ice, etc.

If you look at the Variable declarations of the Code, you can see that we have declared the Variable Y as a simple Variant Type and not as an Array Variable.

The FILTER() function automatically resizes the target array based on the filter operation result. Because the number of matches can vary with each search, the output array can be of different sizes each time. To handle this dynamically, we use the UBound() function to determine the number of elements in the filtered array. This allows a For...Next loop to iterate through all matching items and format them for display in a form MsgBox or other output.

Important points:

  • The source array must be single-dimensional.

  • The search text can be multiple pieces of information: first name, last name, and address.  You should concatenate all relevant fields into a single string for each record and store them in a single-dimensional array.

The Filter() Function will not work in Code Modules of Forms or Reports.

Real Application Around the Filter() Function

I have developed an Application around this Function for our Department Secretary to find Office Files with their location addresses (we have hundreds of them) that match a specific word or phrase in their Subject or Description Fields and display them in a ListBox on a Form.

We will try a similar example using employee data, with more than one field, joined together as source Array contents, and display the Filter result in a ListBox. I will give details of this example in the next Article.

In the meantime, you can experiment with using this function for your own tasks. Once I present my example, you can compare it with your approach and examine the differences or improvements.

If you do it differently, share that idea with me, so that I can learn something new from you, too.

Share:

Dynamic ListBox ComboBox Contents

Dynamic ListBox ComboBox Contents.

Sometimes, you may want to display different sets of unrelated data in the same ListBox — each with its own column layout — and switch between them at will. This switch could happen when the user clicks a button or triggers another event.

Normally, when creating a ListBox or ComboBox in MS Access, you choose one of three standard Row Source Type options: Table/Query, Value List, or Field List. You then set other properties such as Column Count, Column Widths, and Bound Column.

However, there’s another, often overlooked option — you can assign a User-Defined Function to the Row Source Type property. This function can dynamically populate the List Box or ComboBox, allowing full control over the data and its layout.

Interestingly, although it is called a user-defined function, this feature is built into Microsoft Access. The documentation provides the function structure, required parameters, and a basic code template. All you need is to copy the Function and customize it to meet your specific requirements.

You can view the function details in the Access Help Documents. Place the insertion point in the Row Source Type Property of a List Box or Combo Box control and press F1.

When the Help window opens, locate the hyperlink titled User-defined Function and select it. This gives the function parameter details and explains each one's purpose.

We will examine the second example given in the Help document. The VBA code below shows how the function is used in a ListBox, which demonstrates its behaviour and structure.

Function ListMDBs(fld As Control, ID As Variant,  row As Variant, col As Variant,  code As Variant) As Variant
Static dbs(127) As String, Entries As Integer    
Dim ReturnVal As Variant

ReturnVal = Null
    Select Case code
        Case acLBInitialize
               ' Initialize.
            Entries = 0
            dbs(Entries) = Dir("*.MDB")
            Do Until dbs(Entries) = "" Or Entries >= 127
                Entries = Entries + 1
                dbs(Entries) = Dir
            Loop
            ReturnVal = Entries
        Case acLBOpen ' Open.
            ' Generate unique ID for control.
            ReturnVal = Timer
        Case acLBGetRowCount
            ' Get number of rows.
            ReturnVal = Entries
        Case acLBGetColumnCount
    ' Get number of columns.
            ReturnVal = 1
        Case acLBGetColumnWidth
   ' Column width.
   ' -1 forces use of default width.
            ReturnVal = -1
        Case acLBGetValue   ' Get data.
            ReturnVal = dbs(row)
        Case acLBEnd  ' End.
            Erase dbs
    End Select
    ListMDBs = ReturnVal
End Function
  1. Copy the above code into a new Standard Module in your Database and save it.

  2. Open a new Form in Design View and add a ListBox.

  3. Click on the List Box to select it.

  4. Display the Property Sheet (View -> Properties).

  5. Insert the Function name ListMDBs in the Row Source Type Property, overwriting the value Table/Query.

  6. Save the Form.

  7. Open the Form in the normal view.

A list of databases from the specified directory (check Tools -> Options -> General Tab for your default directory location) will appear in the List Box. A sample image of a ListBox is given below:


Taking Files-List From a Specific Folder.

You can modify the following line in the program to list Word or Excel files either from the default folder or from a specific folder of your choice.

dbs(Entries) = Dir("*.xls")

OR

dbs(Entries) = Dir("C:\My Documents\*.xls"). The dbs(Entries) = Dir in the subsequent calls uses the first call parameter value "C:\My Documents\*.xls" by default and populates the String Array dbs() in the Initialize step of the Program.

This code segment is customized and used for various purposes. After the initialization phase, the system repeatedly calls the function to retrieve additional values—such as the row count, column count, and other properties—that determine the ListBox’s property values, which are normally set manually at design time.

When the ColumnWidths Property is -1, Access retains the default settings manually specified in the Property Sheet. This feature is useful when displaying multiple columns of data with mixed column widths.

Finally, the following statements pass the ListBox Source Values dbs(row) that we have created under the Initialize stage for displaying in the ListBox:

Case acLBGetValue: Get data.
ReturnVal = dbs(row)

The Row parameter holds the actual number of items loaded into the dbs() array, which was initially declared with 127 elements. This value is passed to the function through the Entries variable, as shown in the following segment of the code.

Case acLBGetRowCount ' Get the number of rows.
ReturnVal = Entries

The dbs variable is declared as a static, single-dimensioned array with 128 elements (indexed from 0 to 127) so that it retains its values during subsequent calls to the ListMDBs user-defined function. This persistence is important because MS Access calls the function repeatedly at different stages of the ListBox population process. During each of these calls, the required parameter values are automatically passed by MS Access — you don’t need to provide them manually.

The first parameter represents the ListBox control name. The second parameter, ID, helps the system distinguish this specific process from other similar ones that may be running. It is assigned a value based on the System Timer using the following statements:

Case acLBOpen ' Open.
' Generate a unique ID for control.
ReturnVal = Timer

The System Timer generates random values at millisecond intervals, ensuring that each function call receives a unique ID.

The Code parameter carries specific values evaluated in the SELECT CASE statements. These values identify the property or action by Microsoft Access, and the corresponding return values dynamically define or update the List Box property settings.

Using Table Record Field Values in a ListBox.

If you’ve understood, or at least have a general idea of, how this function defines the contents of a List Box or Combo Box, then we’re ready to move on to the interesting part — the trick I mentioned at the beginning of this article.

Second Example with Employees Table

We will use the VBA Code with a few changes for a ListBox that displays two columns — Employee Code and First Name — from the Employees table in the Northwind database.

  1. Import the Employees Table from C:\Program Files\Microsoft Office\Office11\Samples\Northwind.mdb.

  2. Copy the following VBA Code into the Standard Module of your database and save the Module:

    Function ListBoxValues(fld As Control, ID As Variant, row As Variant, col As Variant, code As Variant) As Variant
        Static xList(127, 0 To 1) As String, Entries As Integer
        Dim ReturnVal As Variant, k As Integer
        Dim db As Database, rst As Recordset, recCount As Integer
    
        ReturnVal = Null
        Select Case code
            Case acLBInitialize  ' Initialize.
                Set db = CurrentDb
                Set rst = db.OpenRecordset("Employees", dbOpenDynaset)
                Entries = 0
                Do Until rst.EOF
                   For k = 0 To 1
                        xList(Entries, k) = rst.Fields(k).Value
                   Next
                   rst.MoveNext
                   Entries = Entries + 1
                Loop
                rst.Close
                ReturnVal = Entries
            Case acLBOpen                    ' Open.
                ' Generate unique ID for control.
                ReturnVal = Timer
            Case acLBGetRowCount
             ' Get number of rows.
                ReturnVal = Entries
            Case acLBGetColumnCount
       ' Get number of columns.
                ReturnVal = 2
            Case acLBGetColumnWidth    ' Column width.
               ' -1 forces use of default width.
                ReturnVal = -1
            Case acLBGetValue                ' Get data.
                ReturnVal = xList(row, col)
            Case acLBEnd                        ' End.
                Erase xList
        End Select
        ListBoxValues = ReturnVal
    End Function
  3. Open the Form in Design View with the ListBox we created earlier.

  4. Click on the List Box to select it.

  5. Display the Property Sheet (View -> Properties).

  6. Change the Column Widths Property Value to 0.5";1.5"

    The following lines of Code say to use the values set in the Column Widths property without change:

    Case acLBGetColumnWidth  ' Column width -1 forces the use of the default width.

    ReturnVal = -1

    If the Column Widths property contains only a single value (for example, 1"), then all columns in a multi-column list will automatically use that same width. This may not look visually appealing when the column values vary in length. You may run experiments with different width settings to better understand how they affect the List appearance.

  7. Create a Command Button on the Form.

  8. Ensure that the CommandButton is active and display the Property Sheet.

  9. Click on the On Click Property and select [EventProcedure] from the drop-down control, and click on the Build (...) Button to open the VBA Module with the skeleton of the On Click Event Procedure.

  10. Copy and paste the following lines of code in the middle of the Event Procedure.

    Me.List40.RowSourceType = "ListMDBs"
    Me.List40.Requery
    
  11. Change the name of the List Box (the name in Bold Letters) to match the name of your own List Box.

  12. Create another CommandButton below the first one.

  13. Repeat the Procedure in Steps 10 and 11 for the On Click Property of the second CommandButton.

  14. Copy and paste the following code in the middle of the On Click Event Procedure:

    Me.List40.RowSourceType = "ListBoxValues"
    Me.List40.Requery
    
  15. Change the name of the ListBox (the name in Bold Letters) in the Code to match the name of your own ListBox.

  16. Save and Close the Form.

  17. Open the Form in Normal View.

    Since you have already inserted the ListMDBs User Defined Function in the Row Source Type Property earlier, the list of databases will appear in the List Box first.

  18. Click on the second CommandButton to change the ListBox contents to the Employees List.

    A sample image of the ListBox with the Employee List is given below:

  19. The CommandButton clicks the ListBox contents back to the Database List.

The same procedure works in the ComboBox also. You may create a ComboBox control and run the same functions from the Row Source Type Property.

Don't forget to set the Default Value Property value to 1; otherwise, the ComboBox may not show anything in its TextBox area before you select an item from the list.

Share:

Office Assistant And Msgbox Menus-3

After Clickable Menu Options - Access 2003.

After reviewing the earlier articles on this topic, I hope readers are now familiar with the Microsoft Office Assistant Balloon Object for MsgBox. With just a few lines of customizable VBA code, you can display message boxes with formatted text—using colors, underlines, and even your favorite images. These balloons can also include menus to capture user responses, besides standard buttons like OK, Cancel, Yes, and No.

Since this article is the third part of the series, I recommend that new readers of this topic go through the earlier articles to learn these simple tricks in MS Access before continuing. Links to those articles are provided below:

Last week, we learned how to display Clickable Menu Options in a Balloon Object using Office Assistant. The Image of that example is given below.

We have displayed the Menu Options in the Message Box using the Labels Property of the Balloon Object.

Checkbox Menu Options.

In this section, we will learn how to display checkbox menu options in a balloon message box and how to capture and process user responses. You will also see how to execute specific actions based on the choices. The example code and a sample image of the message box with the checkbox menu are provided below:

Public Function ChoicesCheckBox()
Dim i As Long, msg As String
Dim bln As Balloon, j As Integer
Dim selected As Integer, checked As Integer

Set bln = Assistant.NewBalloon
With bln
    .Heading = "Select Data Output Option"
    .Checkboxes(1).text = "Print Preview."
    .Checkboxes(2).text = "Export to Excel."
    .Checkboxes(3).text = "Datasheet View."
    .Button = msoButtonSetOkCancel
    .text = "Select one of " & .Checkboxes.Count & " Choices?"
    i = .Show

    selected = 0
    If i = msoBalloonButtonOK Then
        'Validate Selection
        For j = 1 To 3
            If .Checkboxes(j).checked = True Then
                selected = selected + 1
                checked = j
            End If
        Next

       'If User selected more than one item
        'then re-run this program and force the
        'User to select only one item as suggested
        'in the message text.

        If selected = 0 or selected > 1 Then
           Call ChoicesCheckBox
        Else
            Select Case checked
                Case 1
                    Debug.Print .Checkboxes(checked).text
                Case 2
                    Debug.Print .Checkboxes(checked).text
                Case 3
                   Debug.Print .Checkboxes(checked).text
            End Select
        End If
    End If
End With

End Function

Like the Labels Property Array, the dimension is five CheckBoxes only.

In our earlier example, we did not use the OK or Cancel buttons alongside the label-based menu because the Balloon Button (msoBalloonTypeButtons) options were directly clickable. Clicking an item both registered the selection and dismissed the Office Assistant. The index number of the clicked item was returned, making it straightforward to check the selection and execute the corresponding action.

But in the case of checkboxes, this is a little more complex because of the following reasons:

  1. The checkboxes can be checked or unchecked, and their state must be validated. 

  2. The user may select one or multiple options simultaneously. If multiple selections are not allowed, the validation check should enforce the limit of only one item. 

  3. Conversely, if multiple selections are permitted, the program must handle and execute the corresponding actions for each selected option. 

  4. In either case, necessary to inspect the selected state of each element in the CheckBox array to determine the menu selection.

Validating the Checked/Unchecked Items

In the example code given above, the User can select only one item at a time.

  • The first step checks whether the user clicked the OK button. If she did, the program counts all the check-marked items and stores the total in the variable selected.

  • If selected is zero (the user clicked OK without selecting any option) or greater than one, the ChoicesCheckBox() function is called again. This refreshes the menu, clears any existing check marks, and displays it again, forcing the user to select a single item or allowing her to select Cancel.

  • It executes the valid selection corresponding to the user’s choice.

  • If multiple selections are permitted, the validation logic and action execution will differ, and the code must be written accordingly to handle all selected items.

The Office Assistant Balloon Object, introduced and explained in these articles, provides a solid foundation for learning the basic features and its properties.

However, duplicating and customizing this code across multiple programs for different needs is not advisable. Doing so increases the database size, reduces code flexibility, and is generally poor programming practice.

You may refer to the earlier published articles (links provided below), which demonstrate how to define public functions such as MsgOK(), MsgYN(), MsgOKCL() and others using the Office Assistant. These functions simplify the use of this feature, allowing you to call them anywhere in your programs—just like the standard MsgBox() function—without duplicating code.

The function names themselves indicate the type of buttons that will appear in the message box when called, either with just a message text or with a message text and title.

  1. Message Box using Office-Assistant
  2. Message Box with Options Menu
  3. Office Assistant with CheckBox Menu

For reference, a comparison between the above user-defined functions and the standard MsgBox() function is provided below. Note that the underscore ( _ ) character is used to indicate line continuation in the code. If you place all values on a single line, the underscore character should not be used.


MS-Access MsgBox() usage Office-Assistant-based User Defined Function usage
MsgBox "Welcome to Tips and Tricks"MsgOK "Welcome to Tips and Tricks"
X = MsgBox("Shut Down Application", vbQuestion+vbDefaultButton2+vbYesNo, _"cmdClose_Click()")X = MsgYN("Shut Down Application", _ "cmdClose_Click()")
X = MsgBox( "Click OK to Proceed or Cancel?", _ vbOKCancel+vbDefaultButton2+vbQuestion, _ "MonthEndProcess()")X = MsgOKCL("Click OK to Proceed or Cancel?", _
"MonthEndProcess()")

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