Can't deselect item in non-multi-select listbox?

AOB

Registered User.
Local time
Today, 19:57
Joined
Sep 26, 2012
Messages
637
I'm embarrassed to even ask this question but for some reason I can't figure it out...

Very, very simple problem - I have a ListBox that has Multi-Select set to None (i.e. only allow one item to be selected at any time)

When I select an item, I can't seem to deselect it again? I can only change which item is selected? Have tried holding Shift when clicking, the item will not deselect?

Am I missing something glaringly obvious? (Apologies, I haven't developed in Access in years and I just can't remember the vagaries of listboxes... :oops:)

Thanks!
 
That's normal behavior.

What about adding a double click event to set the listbox =null?
 
I something add a Clear button next to the listbox. Same as the double click idea, but makes it obvious. If using the dblclick then add the label too. "Double click to Clear list"
 
The "ESC" key can act as a "spot UNDO" for controls. Have you tried that?
 
Thanks everybody. All coming back to me now... Why would that be normal behaviour by design I wonder? Surely there should be a native / intuitive method of undoing the selection rather than having to implement one via code?

For what it's worth, I've decided to go with this as it replicates the "deselect" behaviour of the multi-select version which users (myself included!) will probably try instinctively (I do appreciate that it doesn't check to confirm that the user is clicking on the actual selected item as opposed to some arbitrary other item but I don't think that's going to be too much of an issue...)

Code:
Private blnCtrlKeyPressed As Boolean

Private Sub lst_KeyDown(KeyCode As Integer, Shift As Integer)
    If (Shift And acCtrlMask) > 0 Then
        blnCtrlKeyPressed = True
    End If
End Sub

Private Sub lst_KeyUp(KeyCode As Integer, Shift As Integer)
    blnCtrlKeyPressed = False
End Sub

Private Sub lst_AfterUpdate()
    With Me
        If blnCtrlKeyPressed Then
            .lst.Value = ""
        End If
    
        If Len(.lst.Value) > 0 Then
           ...
        Else
           ...
        End If
    End With
End Sub
 
Perhaps a custom class? Not extensively tested but appears to work well. Example attached.

In a class Module:
Code:
Option Compare Database
Option Explicit

Private WithEvents m_objlbx As Access.ListBox
Private m_oldVal As Variant
Private m_newVal As Variant

Sub initLBX(Lb As ListBox)

    Set m_objlbx = Lb

    m_oldVal = m_objlbx.Value

    m_objlbx.OnClick = "[Event Procedure]"

End Sub

Private Sub m_objlbx_Click()

    m_newVal = m_objlbx.Value
  
    If m_newVal = m_oldVal Then
  
        m_objlbx.Value = Null
      
        m_oldVal = Null
      
    Else
  
        m_oldVal = m_objlbx.Value
    
    End If

End Sub

Public Property Get oldVal() As Variant: oldVal = m_oldVal: End Property

Public Property Get newVal() As Variant: newVal = m_newVal: End Property

Public Property Let newVal(ByVal NewValue As Variant): m_newVal = NewValue: End Property

Public Property Let oldVal(ByVal NewValue As Variant): m_oldVal = NewValue: End Property

Public Property Get lbx() As Access.ListBox: Set lbx = m_objlbx: End Property

Public Property Set lbx(ByVal objNewValue As Access.ListBox): Set m_objlbx = objNewValue: End Property

Form Code:
Code:
Option Compare Database
Option Explicit

Dim clsLbx As clsSingLbx

Private Sub Form_Load()
Set clsLbx = New clsSingLbx
clsLbx.initLBX Me.List0

End Sub
 

Attachments

Last edited:
I tried the escape key. Didn't work for me.
Yeah, that will only work on a new record where it was previously null. If it has a previous value it only goes back to that. It undos not unselects.
 
I've tested that class on bound, unbound, query based, and value list listboxes and it seems to work flawlessly so far.
I'm not quite sure if or where I might use it but I'll stick it in my Application Parts templates just in case.


DeSelect.gif
 
Last edited:
you may try to Add a command button (cmdClearSelection) on your form
to "clear" the selection from the listbox.
add code to its Click Event to do the actual clearing:
Code:
Private Sub cmdClearSelection_Click()
    Dim i As Integer
    For i = 0 To Me.YourListboxName.ListCount - 1
        Me.YourListboxName.Selected(i) = False
    Next
End Sub

or
Code:
Private Sub cmdClearSelection_Click()
    Dim var
    For Each var In Me.YourListboxName.ItemsSelected
        Me.YourListboxName.Selected(var) = False
    Next
End Sub
 
Last edited:
Not being able to revert to null affects two other controls as well.
In an option group you can deselect a selection in the double click event

Code:
Private Sub Frame3_DblClick(Cancel As Integer)

Me.Frame3 = Null

End Sub

With a check box there are 2 options.

Set the triple state setting to yes and it will cycle through Yes, No, Null

Or use the double click event

Code:
Private Sub Check12_DblClick(Cancel As Integer)
Me.Check12 = Null
End Sub
 
This has escalated... :ROFLMAO:

I'm actually going to solve the problem by replacing the listbox with a subform that looks like a listbox (for a variety of reasons, but one of the upshots is that you can customise the select / deselect behaviour far more easily - that's not the primary reason for the switch though...)

Running into another problem but I'll start a new thread as it's technically a different problem to this one but I'll link to it here...
 
Last edited:
but one of the upshots is that you can customise the select / deselect behaviour far more easily
I think I'd disagree with you on that, at least in the context of your original question.
I'll venture a guess that your not that familiar with custom classes. The beauty of them is that you write them once and can then use them in any project with very little code and no modifications.

With the example posted above, you need only to import the class module into your project. You do not need to make any changes or modifications to it. You don't even need to really understand it.

In your form containing the listbox, or listboxes, you only need 3 lines of simple code.

In the declarations section of your form you declare a module level variable for the class object - Dim clsLbx As clsSingLbx

In the OnLoad event of your form you instantiate an instance of the class - Set clsLbx = New clsSingLbx
and initialize it by passing your list box object to the class - clsLbx.initLBX Me.TheNameOfYourListbox

The only change is replacing Me.TheNameOfYourListbox with the name of your list box.

Doesn't get much easier than that.
 
No, agreed, and I do use custom classes elsewhere.

In this particular case though, the restrictions of using a listbox control make a subform a better alternative. What I'm trying to do is create a kind of template for manipulation of "static data" within the DB. So a basic form that can be replicated multiple times depending on which table / tables need to be manipulated.

With a listbox, you can only select an item. With a continuous subform, you can add command buttons to each record and fire functions specific to that record from within the subform. That is the true motivation for switching from a listbox to a subform. The added benefit with subforms just happens to be that I can simultaneously impose my own select / deselect behaviour far more easily than with a "stock" listbox. Yes, I can impose that same behaviour with a custom class - but I can't make a listbox host buttons!
 
Except that they can sort of look similar, they are different objects and used for different purposes for different kinds of data.

A single select listbox is a control that is bound to one column of one row. A subform is bound to a table/query of multiple columns and multiple rows. They are not interchangeable.

Yup, totally accept that, and agree. What I'm saying is, there are situations where I want something bound to multiple rows and columns?
 
Then you never had a single column to begin with. Have we moved on to a new problem since this is not the solution to the problem you came here with?

Sorry, yes... I guess so, yes.

My original problem was providing an intuitive method to allow users to deselect an item in a listbox. As I explored options, I discovered that a continuous subform, as an alternative to the listbox, would solve a different set of problems that arose (nothing to do with item selection).

But it so transpired that it also solved this problem because I could control / manipulate the selection behaviour in the subform, more easily than with the listbox. So, yes, you are correct, apologies for the crossed wires there! :oops:
 
My original problem was providing an intuitive method to allow users to deselect an item in a listbox
It would have been a neat way to check for a pressed special key (Ctrl, Alt, Shift) on the click event and then assign zero to the list field.
 
It would have been a neat way to check for a pressed special key (Ctrl, Alt, Shift) on the click event and then assign zero to the list field.

Yes, see post #5 in this thread (pretty much what you're describing)
 
Code:
Private Declare Function GetKeyState% Lib "user32" (ByVal vkey As Long)

Private Sub MyListBox_Click()
   If Abs(GetKeyState(17) < 0) Then                  ' CTRL+
      Me.MyListBox = NULL
   End If
End Sub
 
There is one more option that I think is not exposed and that is to place it as the first row (Select a row) and this first row deselects all the others but will not be taken into account.
Or also say "unselect here"
Nothing out of this world but it is an option
 

Users who are viewing this thread

Back
Top Bottom