MSForms.ListBox VBA 如何自定义多选?

How to costumize MultiSelect for MSForms.ListBox VBA?

嗨,我想实现以下目标:

我有一个带有列表框的用户窗体。此列表框应具有以下选择行为:

这是我的列表框:

1 鼠标点击切换选择

2 在按住鼠标按钮单击的同时移动到项目上将切换选择

遗憾的是,此行为与 3 个可选的 MultiSelect 属性不匹配。

0- fmMultiSelectSingle

1-fmMultiSelectMulti

非常接近但是:

2-fmMultiSelectExtended

也很接近但是:

总而言之,目标是通过单击或在单击鼠标时在它们上方移动来手动切换所有项目

我尝试用 ListBox_Change 事件来做,但我不知道怎么做..

这是我试过的代码:

通用用户窗体:

Private Type TView
    SelectedCol As Collection
    EventsDisabled As Boolean
End Type

Private this As TView

Public Property Get SelectedCol() As Collection
    Set SelectedCol = this.SelectedCol
End Property
Public Property Set SelectedCol(ByVal value As Collection)
    Set this.SelectedCol = value
    'Validate
End Property

Private Sub UserForm_Initialize()
Set SelectedCol = New Collection
counter = 0
Dim i As Integer

For i = 1 To OptionList.ListCount
    SelectedCol.Add Me.OptionList.Selected(i)
Next i
End Sub

UpdateSelectedCol 子:

Sub UpdateSelectedCol()
Dim i As Integer
Dim bo As Boolean
For i = OptionList.ListCount To 1
    SelectedCol.Remove (i)
Next i
For i = 1 To OptionList.ListCount
    SelectedCol.Add OptionList.Selected(i - 1)
Next i

End Sub

ListBox_Change 事件:

Private Sub OptionList_Change()
Dim i As Integer
If this.EventsDisabled = False Then
    this.EventsDisabled = True
    GO_btn.Enabled = ISSelected(Me.OptionList)
    
    ' keep selected until changed
    For i = 1 To Me.OptionList.ListCount
        If SelectedCol.Item(i) Then
            Me.OptionList.Selected(i) = True
        End If
    Next i
    
    Debug.Print SelectedCount(Me.OptionList)
    UpdateSelectedCol
End If
this.EventsDisabled = False
End Sub

So what I tried was the following: When the Selection gets changed it will compare if that element was selected before and will keep it.这不会稍微改变 MultiSelect 的行为。我认为至少应该保留所有已选择一次的项目。

编辑:添加了一些图片和代码作为我尝试过的示例,以及它应该如何运行。

好的,我明白了:

首先,您从 1-MultiSelectMulti 作为 ListBox 属性 开始。比您将以下代码添加到您的用户表单:

解决方案

Private Sub OptionList_Change()
Dim i As Integer
If Not this.EventsDisabled Then
    this.EventsDisabled = True
    GO_btn.Enabled = ISSelected(Me.OptionList)
    
    ' MAIN SOLUTION ************************************************

    ' if has changed keep odl value when not = to listindex
    For i = 1 To Me.OptionList.ListCount
        If Me.OptionList.Selected(i - 1) <> SelectedCol.Item(i) And Not i - 1 = Me.OptionList.ListIndex Then
            ToggleItem (i)
        End If

    ' MAIN SOLUTION END ************************************************
        
    UpdateSelectedCol
    this.EventsDisabled = False
End If
End Sub

最好的线索是 .ListIndex 属性,它告诉您“光标”在列表中的位置。这也是按住鼠标时鼠标所在的位置。所以你所要做的就是:

如果一个列表项的值发生变化,并且列表索引不等于更改项的索引,则将该项切换回初始状态。

先决条件

Private Type TView
    SelectedCol As Collection
    EventsDisabled As Boolean
End Type

Private this As TView

Public Property Get SelectedCol() As Collection
    Set SelectedCol = this.SelectedCol
End Property
Public Property Set SelectedCol(ByVal value As Collection)
    Set this.SelectedCol = value
    'Validate
End Property

Private Sub UserForm_Initialize()
Set SelectedCol = New Collection
counter = 0
Dim i As Integer

For i = 1 To OptionList.ListCount
    SelectedCol.Add Me.OptionList.Selected(i - 1)
Next i

End Sub


Sub ToggleItem(i As Integer)
    Me.OptionList.Selected(i - 1) = Not Me.OptionList.Selected(i - 1)
End Sub

Sub UpdateSelectedCol()
this.EventsDisabled = True
Dim i As Integer
Dim bo As Boolean
For i = OptionList.ListCount To 1 Step -1
    SelectedCol.Remove (i)
Next i
For i = 1 To OptionList.ListCount
    SelectedCol.Add OptionList.Selected(i - 1)
Next i
this.EventsDisabled = False
End Sub

您需要在同一个用户表单中满足先决条件才能正常工作。我认为 UpdateSelectedColtoggleitem 很容易重构。