ListBox Comparison (1 Viewer)

Aoife

Registered User.
Local time
Today, 20:49
Joined
Dec 4, 2013
Messages
36
Hi

I'm attempting to use 2 listboxes to book out listings of pupils to various activities. In my code below, List11 is the list of all pupils, whereas List79 is based on a query where the activities are logged. The code below iterates though the selected pupils in List11 and populates List79 but it duplicates pupil names rather than overwriting any existing pupil names with most up to date details.

I've attempted numerous ways of looping through the list boxes in order not to duplicate any names already on List79 but keep making a mess of it. A few pointers would be great

Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim ctl As Control
Dim varItem As Variant
'On Error GoTo ErrorHandler
Set db = CurrentDb()
Set rs = db.OpenRecordset("PupilDetailsquery", dbOpenDynaset)
If Me.List11.ItemsSelected.Count = 0 Then
MsgBox "A record must be selected"
Exit Sub
End If

For Each varItem In Me.List11.ItemsSelected
rs.AddNew
rs!nameofpupil = Me.List11.Column(1, varItem)
rs.Update
Next varItem
rs.Requery
Me.List79.Requery
 

Cronk

Registered User.
Local time
Tomorrow, 05:49
Joined
Jul 4, 2013
Messages
2,771
One way is to have a Yes/no field in your tblPupils indicating whether the record is selected or not. Call the field RecSelected.


Tip: if you are going to refer to controls in code, give them a meaningful name ie not List11 but lstNotSelected


me.lstNotSelected.rowsource = "select ... where RecSelected = false"
me.lstSelected.rowsource="select ... wher RecSelected = true"


Initialise with a query to set RecSelected to false
Loop through lstNotSelected and update RecSelected to True.
Requery both list boxes.


You can do the same on lstSelected to deselect.


If you are repeating for another activity, then updating the combo box showing the activity should trigger a reset of the process.
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 15:49
Joined
May 21, 2018
Messages
8,525
You probably have to clear out the list before adding to it.
Code:
Public Sub ClearList(lst As Access.ListBox)
  Dim lstItem As Integer
  For lstItem = lst.ListCount - 1 To 0 Step -1
    lst.RemoveItem (lstItem)
    'Debug.Print "remove"
  Next lstItem
End Sub
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 15:49
Joined
May 21, 2018
Messages
8,525
I have a generic "From To List" control built as a subform. I will load that up later. But here are some helpful procedures to populate and move things between the two lists.

Code:
Public Sub MoveFromListToList(SourceList As ListBox, DestinationList As ListBox)
  Dim varItem As Variant
  Dim strAdd As String
  Dim columnCount As Integer
  Dim i As Integer
  columnCount = SourceList.columnCount
  For Each varItem In SourceList.ItemsSelected
     For i = 0 To columnCount - 1
        If strAdd = "" Then
           strAdd = SourceList.Column(i, varItem)
        Else
           strAdd = strAdd & ";" & SourceList.Column(i, varItem)
        End If
     Next i
      DestinationList.RowSourceType = "value list"
      DestinationList.AddItem strAdd
      strAdd = ""
  Next varItem
  'remove from source
  RemoveFromList SourceList
End Sub

Public Sub RemoveFromList(SourceList As ListBox)
  Dim i As Integer
  Dim tempCol As New Collection
  Dim varitm As Variant
  'once you delete an item it clears the itemselected
  'so you need to store these values
  'must remove in descending order
  For Each varitm In SourceList.ItemsSelected
    tempCol.Add (varitm)
    If SourceList.Name = Me.ListFrom.Name Then
      'Remove from From list adding to To list
      RaiseEvent ItemToAdded(SourceList.Column(Me.BoundColumn, varitm))
    Else
      RaiseEvent ItemFromAdded(SourceList.Column(Me.BoundColumn, varitm))
    End If
  Next
  For i = tempCol.Count To 1 Step -1
    SourceList.RemoveItem (tempCol(i))
  Next i
End Sub
Public Sub MoveAll(SourceList As ListBox, DestinationList As ListBox)
  Dim lstItem As Integer
  
  For lstItem = 0 To SourceList.ListCount - 1
    SourceList.Selected(lstItem) = True
  Next lstItem
  
  MoveFromListToList SourceList, DestinationList
End Sub

Public Sub ClearList(lst As Access.ListBox)
  Dim lstItem As Integer
  For lstItem = lst.ListCount - 1 To 0 Step -1
    lst.RemoveItem (lstItem)
    'Debug.Print "remove"
  Next lstItem
End Sub

Public Sub LoadFrom()
  Dim rs As DAO.Recordset
  Dim strAdd As String
  Dim fld As DAO.Field
  ClearList Me.ListFrom
  Set rs = CurrentDb.OpenRecordset(Me.From_SQL)
   Do While Not rs.EOF
   strAdd = ""
   For Each fld In rs.Fields
     If strAdd = "" Then
       strAdd = rs.Fields(fld.Name).Value
     Else
       strAdd = strAdd & ";" & rs.Fields(fld.Name).Value
     End If
   Next fld
   Me.ListFrom.AddItem strAdd
   rs.MoveNext
  Loop

End Sub

Public Sub LoadTo()
  Dim rs As DAO.Recordset
  Dim strAdd As String
  Dim fld As DAO.Field
  ClearList Me.ListTo
  Set rs = CurrentDb.OpenRecordset(Me.To_SQL)
   Do While Not rs.EOF
   strAdd = ""
   For Each fld In rs.Fields
     If strAdd = "" Then
       strAdd = rs.Fields(fld.Name).Value
     Else
       strAdd = strAdd & ";" & rs.Fields(fld.Name).Value
     End If
   Next fld
   Me.ListTo.AddItem strAdd
   rs.MoveNext
  Loop
End Sub

Public Sub LoadLists()
  LoadTo
  LoadFrom
End Sub

Public Function GetListItems(SourceList As ListBox) As Collection
  Dim lstItem As Integer
  Set GetListItems = New Collection
  For lstItem = 0 To SourceList.ListCount - 1
    GetListItems.Add (SourceList.Column(Me.BoundColumn, lstItem))
  Next lstItem
End Function
 

Aoife

Registered User.
Local time
Today, 20:49
Joined
Dec 4, 2013
Messages
36
Thanks for the link JDraw - opened my eyes to the Yes/No field that Cronk also kindly highlighted along with the method I'll probably attempt to progress tomorrow.

Example code was also very useful MajP, would still appreciate your subform example

Cheers All
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 15:49
Joined
May 21, 2018
Messages
8,525
The intent was to build a subform to basically function as a generic "From To List" where you can move thing between lists and be reused on any list without having to rewrite any code. All functionality is contained in the subform so it basically functions like an embedded control.

Basically you pass in the starting sql strings for the left left (from) and right list (to). Tell it the bound column. After that you trap the custom event in your main form, and can do that to do whatever you want. Normally that would be some kind of update, delete, or append query. But basically all the functionality you see can be done from any form with these lines of code

Code:
Public WithEvents FormFromTo As Form_FromToList
Private Sub Form_Load()
  Set FormFromTo = Me.frmFromToList.Form
  Dim FromSql As String
  Dim ToSql As String
  FromSql = "some sql string"
  ToSql = "Some other sql string or optional if not starting with selected items"
  'Initialize the class
  FormFromTo.InitializeFromTo FromSql, ToSql, "Employees Not Selected", "Employees Selected"
End Sub

'Trap the custom event and do something
Private Sub FormFromTo_ItemFromAdded(Item As Variant)
  Dim strSql As String
   'Now run delete query
  strSql = "Delete * from tblSelectedEmployees where SelectedemployeeID = " & Item
  CurrentDb.Execute strSql
  Me.subfrmSelectedEmployees.Form.Requery
End Sub

Private Sub FormFromTo_ItemToAdded(Item As Variant)
  Dim strSql As String
   'Now run insert query
  strSql = "Insert into tblSelectedEmployees (SelectedEmployeeID) Values (" & Item & ")"
  CurrentDb.Execute strSql
  Me.subfrmSelectedEmployees.Form.Requery
End Sub
 

Attachments

  • FromToList Generic SingleSelect v2.accdb
    712 KB · Views: 91
Last edited:

arnelgp

..forever waiting... waiting for jellybean!
Local time
Tomorrow, 03:49
Joined
May 7, 2009
Messages
19,229
I vote for Cronks approach.
does not need to delete records everytime (thereby preventing bloat on the db).
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 15:49
Joined
May 21, 2018
Messages
8,525
Code:
Does not need to delete records everytime (thereby preventing bloat on the db).
Totally missed the point. That was just an example, the code is agnostic. Maybe it is a delete query, maybe an insert query, maybe an update query, maybe display only, maybe used to run some other code. It could work with a table that has a "select" like field as well without ever having to write additional code except to load the query string. There is additional methods to return the values at the end instead of trapping every change so you can pull the results at the end. Adding a select field to a table works well, but limited to when you have control of the table structure.
 

Users who are viewing this thread

Top Bottom