Sometimes, the ability to select multiple items from a list would come in very handy. Instead of selecting single items several times, consider placing a List Box control on a form and using its Multi Select property. In this article, we'll show you a technique for adding this functionality to your forms.
The multi select property
By default, the Multi Select property for a list box is set to None. However, you can set this property to Simple or Extended to instantly allow multiple selections to be chosen from within the list box. The Simple setting allows you to point and click at multiple items in the list to select or de-select them. The Extended setting allows you to use the [Shift] and [Ctrl] keys in combination with mouse clicks or arrow keys to select or deselect items in the list.
If you want to bind the List Box control to a field (Control Source), keep the Multi Select property set to None. You do this because if you select more than one item, Access will set the List Box control's value to Null. As you'll see later, you must use the ItemsSelected collection to determine the values or items selected.
A form to update multiple items
Let's work through an example of selecting multiple list-box items. To begin, open a new database and create a table called tblSalesItems with the structure shown in Table A. Save the table and populate it with the seven records shown in the list box in Figure A of "Some List-Box Basics".
Field Name | Data Type |
---|---|
Description | Text 20 (Primary Key) |
SalePrice | Currency |
To demonstrate the list box's Multi Select property, refer to the form shown in Figure A. It uses a list box to display the list of sales items available (the Description and SalePrice of each item). The user can select as many items from this list as desired. We've selected four items in Figure A.
Figure A: This example form uses the Multi Select list box.
Our form also includes a multiplier text box that will change the SalePrice value of items selected in the list box. The default value is 1.00, which won't cause any change (you'd be multiplying the SalePrice by one). But, if you change the value to 1.10, for instance, you'll apply a 10 percent increase to the SalePrice of the items selected.
Finally, the Update button triggers a VBA function to run and update the SalePrice for all items selected. To see the effect of the function on one form, we've placed the list box, multiplier text box, and Update button in the form's Header. The form's Record Source is set to tblSalesItems, so these records appear in the Detail section. When you update selected items, you can see their values change in the Detail section of the form.
Creating the update form
Next, create a form called frmSalePriceUpdate, set its Record Source property to tblSalesItems, and set its Default View to Continuous Forms, as you can see in Figure B.
Figure B: The update form looks like this in design mode.
Turn the form's Header/Footer on by choosing View | Form Header/Footer from the form's design menu. Make the height of the Form Header about two inches. You won't use the Form Footer, so you can make its height zero inches.
In the Form Header, add the List Box control lstSalesItems. Don't use the Control Wizard, if it starts when you create the list box--instead, cancel out of the Wizard and manually set the list-box properties shown in Table B. Also, set the caption of the list box's associated label to Sales Items.
Table B: lstSalesItems list-box properties
Property | Value |
---|---|
Name | lstSalesItems |
Control Source | (blank) |
Row Source Type | Table/Query |
Row Source | tblSalesItems |
Column Count | 2 |
Bound Column | 1 |
Multi Select | Simple |
Next, in the Form Header, add the txtMultiplier text box that will change the SalePrice value of items selected in the list box. Set the text box's properties as shown in Table C.
Table C: txtMultiplier text-box properties
Property | Value |
---|---|
Name: | txtMultiplier |
Control Source: | (blank) |
Format: | Standard |
Decimal Places: | Auto |
Default Value: | 1 |
Now, add the Update button to the Form Header and set its properties as shown in Table D. Enter the following VBA code in the button's On Click event:
Private Sub btnUpdate_Click()
Dim iRetVal As Integer
iRetVal = UpdatePrices()
End Sub
As you can see, you'll be writing a function called UpdatePrices that will take
the selected items and multiply them by the multiplier to get a new SalePrice
for each item.
Table D: Update button properties
Property | Value |
---|---|
Name: | btnUpdate |
Caption: | &Update |
On Click: | [Event Procedure] |
Next, add two labels to the Form Header: Description and Sale Price. Finally, just for cosmetic purposes, you can add a horizontal line between the list box and the two labels.
In the form's Detail section, add two text boxes with the Name property Description and SalePrice and the Control Source Description and SalePrice, respectively. Thus, you'll use these controls to display the data in table tblSalesItems.
As we mentioned earlier, the form's Default View is set to Continuous Forms--this allows Access to display multiple records on a form, as opposed to one record at a time. As a result, you'll be able to select sales items, update the price using the multiplier, and see the price changes--all on the same form.
VBA function to update prices
In the Update button's On Click event, you call a function named UpdatePrices. Listing A shows the code for this function. The function is saved in a module called modMultiSelectListBox (although the module's name has no bearing on the function).
Listing A: UpdatePrices function
Function UpdatePrices() As Integer
'--------------------------------------
' Purpose: Using <frmSalesItems>, use selected entries
` from [lstSalesItems] list box and [txtMultiplier] to
` update [SalePrice] field in <tblSalesItems>.
'--------------------------------------
' By: Pat Steiner
' Date: 6/30/98
' Version: 1.0
'--------------------------------------
Dim DB As Database
Dim RSSales As Recordset
Dim F As Form
Dim sMessage As String
Dim sMsgTitle As String
Dim sFunction As String
Dim sDescription As String
Dim iSelected As Integer
Dim iIndex As Integer
Dim iLoop As Integer
Dim vMultiplier As Variant
'--------------------------------
' 1. Initialize "local" variables and error trap.
'--------------------------------
UpdatePrices = 0
sMessage = ""
sFunction = "UpdatePrices"
sMsgTitle = "FN: " & sFunction & " ( )"
On Error GoTo Err_UpdatePrices
Set DB = CurrentDb()
Set F = Forms![frmSalePriceUpdate]
'--------------------------------
' 2. Make sure form has valid entries: at least 1 item
` selected from list box and Multiplier is not Null.
'--------------------------------
iSelected = 0
iSelected = F![lstSalesItems].ItemsSelected.Count
vMultiplier = 1# 'Default value
vMultiplier = F![txtMultiplier]
If iSelected = 0 Or IsNull(vMultiplier) Then
sMessage = _
"You must select at least 1 entry from SALES LIST "
sMessage = sMessage & "and a % CHANGE value." & _
vbCrLf & vbCrLf
sMessage = sMessage & "- - - PROCESS ABORTED - - -"
Beep
MsgBox sMessage, vbCritical, sMsgTitle
Exit Function
End If
'--------------------------------
' 3. Open the <tblSalesItems> recordsets, [RSSales].
'--------------------------------
Set RSSales = DB.OpenRecordset("tblSalesItems", _
dbOpenTable)
If RSSales.EOF Then
RSSales.Close
sMessage = "Table <tblSalesItems> has no data ..." & _
vbCrLf & vbCrLf
sMessage = sMessage & "- - - PROCESS ABORTED - - -"
Beep
MsgBox sMessage, vbCritical, sMsgTitle
Exit Function
End If
RSSales.Index = "PrimaryKey"
'PrimaryKey is [Description] field
'--------------------------------
' 4. Data table OK ... begin processing selected data in
' the List Box control.
'--------------------------------
For iLoop = 0 To (iSelected - 1)
'ItemsSelected collection is zero-based array
iIndex = F![lstSalesItems].ItemsSelected(iLoop)
sDescription = F![lstSalesItems].ItemData(iIndex)
RSSales.Seek "=", sDescription
RSSales.Edit
RSSales![SalePrice] = RSSales![SalePrice] * vMultiplier
RSSales.Update
Next iLoop
'--------------------------------
' 5. Close recordset.
'--------------------------------
RSSales.Close
'--------------------------------
' 6. Refresh form data.
'--------------------------------
DoCmd.SelectObject acForm, "frmSalePriceUpdate"
DoCmd.ShowAllRecords
'--------------------------------
' 7. Set function value and exit.
'--------------------------------
UpdatePrices = -1 '-1 indicates normal exit
Beep
sMessage = "All selected items were updated OK!"
MsgBox sMessage, vbInformation, sMsgTitle
Exit Function
'================
Err_UpdatePrices:
'================
Select Case Err
Case 94: 'Invalid use of NULL
Resume Next
Case Else:
Beep
sMessage = "Error #" & Err & ": " & Error(Err)
MsgBox sMessage, vbExclamation, sMsgTitle
Exit Function
End Select
End Function
The UpdatePrices function code is well documented, but we'll point out the
sections related to the Multi Select list box. In code section 2, you want to
be sure the user has selected at least one item from the list box and that the
multiplier text box hasn't been set to Null. In either of these cases, there's
no need to proceed, and you display a warning message. In code section 4, you
determine which list box items have been selected, and then perform the price
update on these items.The Multi Select list box has an ItemsSelected collection that stores the list of items selected in the list box. To check how many items are selected in the list box, you use the ItemsSelected.Count property, as in the following line:
iSelected = _
F![lstSalesItems].ItemsSelected.Count
The ItemsSelected collection contains the index or list numbers of the items
selected in the list box. It's zero-based, meaning if you select items 1, 3, 5,
and 6--as we did in Figure A--they're stored in the ItemsSelected
collection as 0, 2, 4, and 5 index values.The list box has a property called ItemData(index) (where index is the value obtained from the ItemsSelected collection). ItemData really contains the data that you want--that is, the names of the items (Description) selected. Referring again to the items selected in Figure A, the following information is stored in the list box:
ItemsSelected.Count = 4
ItemsSelected(0)=0 (1st list box entry)
ItemsSelected(1)=2 (3rd list box entry)
ItemsSelected(2)=4 (5th list box entry)
ItemsSelected(3)=5 (6th list box entry)
ItemData(0)="Golf Balls"
ItemData(2)="Golf Hats"
ItemData(4)="Golf Shoes"
ItemData(5)="Irons"
Testing the form
In Figure C, we've selected four items in our list box.
Figure C: Our form reflects price changes to our multi-selected items.
We've set the multiplier to 1.50 (or a 50 percent price increase). After clicking the Update button, you can see that the selected items shown in the Detail section of the form reflect the new prices. We purposely don't refresh the List Box control in this example, so you can see the changed prices easily.
Conclusion
The List Box control's Multi Select property is a very powerful feature that the Access developer can put to work in form design and use. You need to understand the ItemsSelected collection and the ItemData property values, and some VBA coding is required. We hope that our example application will get your creative juices flowing and take the mystery out of the required VBA programming.