【问题标题】:Excel VBA - How To Deselect A Previosuly Selected Item In A ListboxExcel VBA - 如何取消选择列表框中先前选择的项目
【发布时间】:2016-11-14 00:54:32
【问题描述】:

我的 Excel VBA 项目中有一个用户表单 (uf1_assess_sched),它有一个列表框 (uf1_listbox3)。

当用户选择此列表框中的单个项目时,将打开第二个用户表单 (group_1),允许用户输入特定于她在第一个用户表单上所做选择的信息。如果用户希望放弃对 group_1 的进一步进入,她可以通过单击名为 Exit 的命令按钮退出。

退出时,group_1 被卸载,uf1_assess_sched 走在最前面。这个想法是允许用户从 uf1)listbox3 中选择另一个项目。但是,她最初的选择仍然被选中。

如何取消选择这个先前所做的选择。

我试过了:

With uf1_assess_sched
    .uf1_listbox3.listindex = -1
End With

这是我在任何搜索中都能找到的最相关的。

根据 Patrick 的建议,由于我对 Excel VBA 的了解有限,我是这样解释他的指令的。

With uf1_assess_sched
    For i = 0 To .uf1_listbox3.ListCount - 1
        If .uf1_listbox3.Selected(i) = True Then
            .uf1_listbox3.Selected(i) = False
        End If
    Next i
End With

很遗憾,这没有奏效。代码确实找到了真正的选择,但该条目在列表框中仍然被选中,并且还触发了 uf1_listbox3_Click 事件。

我希望通过简单地编辑我的原始帖子,以适当的方式提供反馈。我不确定如何在评论中添加代码。 StackOverflow 对我来说是一种新格式,所以尽我所能。

使用 Patrick 提供的最新代码,我设法在遇到错误之前做到了这一点。我做了一些修改以反映用户窗体和列表框名称。我收到“未找到方法或数据成员。”第二个用户表单 group_1 中的代码错误。

Private Sub exit1_Click()

Dim ui2 As VbMsgBoxResult
Dim lastrow As Long
Dim i As Long

If ws_vh.Range("E2") > 0 Then 'unsaved info
    Me.Label34.Caption = "    Saving unsaved rental data."
    Me.Label34.BorderColor = RGB(50, 205, 50)
    lastrow = ws_rd.Cells(ws_rd.Rows.Count, "A").End(xlUp).Row
    ws_rd.Range("A3:FZ" & lastrow).Sort key1:=ws_rd.Range("A3"), order1:=xlAscending, Header:=xlNo
    Application.DisplayAlerts = False
    ThisWorkbook.Save
    Application.DisplayAlerts = True

    Debug.Print Me.Name, "exit1_Click() called"
    uf1_assess_sched.ListBox3_DeSelect    '<--- Error with ".Listbox3_DeSelect"
    Unload Me

    'Unload group_1
    'End
    Exit Sub
End If

If ws_vh.Range("B2") > 0 Then   'Outstanding rentals?
    ui2 = MsgBox("You still have " & ws_vh.Range("C2") & " rentals with critical missing rental information." & Chr(13) & Chr(13) _
        & "Active (Sports) rentals: " & ws_vh.Range("B3") & Chr(13) & "Passive (Picnics) rentals: " & ws_vh.Range("B4") & Chr(13) & Chr(13) _
        & "Are you sure you wish to exit?", vbInformation + vbYesNo, "OUTSTANDING RENTAL INFORMATION")
    If ui2 = vbYes Then
        If ws_vh.Range("N4") > 0 Then
            Me.Label34.Caption = "    Saving unsaved rental data."
            Me.Label34.BorderColor = RGB(50, 205, 50)
            lastrow = ws_rd.Cells(ws_rd.Rows.Count, "A").End(xlUp).Row
            ws_rd.Range("A3:FZ" & lastrow).Sort key1:=ws_rd.Range("A3"), order1:=xlAscending, Header:=xlNo
            Application.DisplayAlerts = False
            ThisWorkbook.Save
            Application.DisplayAlerts = True
            Workbooks("Sports15c.xlsm").Activate
            mbEvents = False

            Debug.Print Me.Name, "exit1_Click() called"
            uf1_assess_sched.ListBox3_DeSelect    '<--- Error with ".Listbox3_DeSelect"
            Unload Me
            Exit Sub
        Else
            Unload Me
            End
        End If
    Else
        Exit Sub
    End If
 End If

Unload group_1
End
End Sub

我确实将 subs ListBox1_DeSelect() 和 ListBoxDeSelect(oListBox As Object) 放在了一个单独的模块中(也许这就是问题所在)。

这是代码...

Sub ListBox3_DeSelect()
ListBoxDeSelect Me.uf1_listbox3
End Sub

Private Sub ListBoxDeSelect(oListBox As Object)
Dim i As Long
If TypeName(oListBox) <> "ListBox" Then Exit Sub
bSkipEvent = True
With oListBox
    For i = 0 To .ListCount - 1
        If .Selected(i) Then
            .Selected(i) = False
        End If
    Next
End With
bSkipEvent = False
End Sub

这是我最近的代码(7 月 19 日)...

USERFORM 1 - uf1_assess_sched(保存用户选择的列表框)

Private Sub uf1_listbox3_Click()
    If mbEvents Then Exit Sub
    Debug.Print Me.Name, "uf1_listBox3_Click() called"
    If bSkipEvent Then Exit Sub
    With uf1_listbox3
        Debug.Print Me.Name, "uf1_listBox3_Click() ListIndex: " & .ListIndex & " (" & .List(.ListIndex) & ")"
        group_1.Show
        'UserForm2.TextBox1.Value = .List(.ListIndex) ' This won't have effect if UserForm2 is True on ShowModal
    End With
End Sub

USERFORM 2 - group_1(允许用户根据在 userform1 中选择的值输入其他数据。用户可以通过按 EXIT 按钮 (exit1) 来选择放弃)

Private Sub exit1_Click()

    Dim ui2 As VbMsgBoxResult
    Dim lastrow As Long
    Dim i As Long

    If ws_vh.Range("E2") > 0 Then 'unsaved info
        Me.Label34.Caption = "    Saving unsaved rental data."
        Me.Label34.BorderColor = RGB(50, 205, 50)
        lastrow = ws_rd.Cells(ws_rd.Rows.Count, "A").End(xlUp).Row
        ws_rd.Range("A3:FZ" & lastrow).Sort key1:=ws_rd.Range("A3"), order1:=xlAscending, Header:=xlNo
        Application.DisplayAlerts = False
        ThisWorkbook.Save
        Application.DisplayAlerts = True
        Unload group_1
        'End
        Exit Sub
    End If

    If ws_vh.Range("B2") > 0 Then   'Outstanding rentals?
        ui2 = MsgBox("You still have " & ws_vh.Range("C2") & " rentals with critical missing rental information." & Chr(13) & Chr(13) _
            & "Active (Sports) rentals: " & ws_vh.Range("B3") & Chr(13) & "Passive (Picnics) rentals: " & ws_vh.Range("B4") & Chr(13) & Chr(13) _
            & "Are you sure you wish to exit?", vbInformation + vbYesNo, "OUTSTANDING RENTAL INFORMATION")
        If ui2 = vbYes Then
            If ws_vh.Range("N4") > 0 Then
                Me.Label34.Caption = "    Saving unsaved rental data."
                Me.Label34.BorderColor = RGB(50, 205, 50)
                lastrow = ws_rd.Cells(ws_rd.Rows.Count, "A").End(xlUp).Row
                ws_rd.Range("A3:FZ" & lastrow).Sort key1:=ws_rd.Range("A3"), order1:=xlAscending, Header:=xlNo
                Application.DisplayAlerts = False
                ThisWorkbook.Save
                Application.DisplayAlerts = True
                Workbooks("Sports15c.xlsm").Activate

                Debug.Print Me.Name, "EXIT1_Click() called"
                    'UserForm1.ListBox1_DeSelect ' No longer used.
                Set oListBoxToDeselect = uf1_assess_sched.uf1_listbox3 ' [M2] This is required for the DelayedListBoxDeSelect(), if top right [X] is clicked, it won't do DeSelect
                Unload Me
            Else
                Unload Me
                End
            End If
        Else
            Exit Sub
        End If
     End If
            'If ws_vh.Range("N4") > 0 Then
            '    MsgBox "Unsaved rental data. Saving."
            '    lastrow = ws_rd.Cells(ws_rd.Rows.Count, "A").End(xlUp).row
            '    ws_rd.Range("A3:FZ" & lastrow).Sort key1:=ws_rd.Range("A3"), order1:=xlAscending, Header:=xlNo
            '    Application.DisplayAlerts = False
            '    ThisWorkbook.Save
            '    Application.DisplayAlerts = True
            '    Unload Me
            'Else
            '    Worksheets("DYNAMIC").Activate
            '    Unload Me
            'End If
        'End If
    Unload group_1
    'Worksheets("DYNAMIC").Activate
    End

End Sub

为了测试的目的,假设 ws_vh.Range("B2") > 0

还有独立的辅助模块...

Option Explicit

' Generic ListBox Deselector
Sub ListBoxDeSelect(oListBox As Object)
    Dim i As Long
    If TypeName(oListBox) <> "ListBox" Then Exit Sub
    bSkipEvent = True
    With oListBox
        For i = 0 To .ListCount - 1
            If .Selected(i) Then
                .Selected(i) = False
            End If
        Next
    End With
    bSkipEvent = False
End Sub

' METHOD 2 [M2] - When UserForm's ShowModal = True
Sub DelayedListBoxDeSelect()
    Dim i As Long
    If TypeName(oListBoxToDeselect) <> "ListBox" Then Exit Sub
    bSkipEvent = True
    With oListBoxToDeselect
        For i = 0 To .ListCount - 1
            If .Selected(i) Then
                .Selected(i) = False
            End If
        Next
    End With
    bSkipEvent = False
    Set oListBoxToDeselect = Nothing
End Sub

group_1 用户窗体终止代码

Private Sub UserForm_Terminate()
    Debug.Print Me.Name, "UserForm_Terminate() called"
    Set oListBoxToDeselect = uf1_assess_sched.uf1_listbox3 ' [M2] This is required for the DelayedListBoxDeSelect(), if top right [X] is clicked, it won't do DeSelect
    Application.OnTime Now + TimeSerial(0, 0, 1), "DelayedListBoxDeSelect" ' [M2] Sechedules the Sub named "DelayedListBoxDeSelect" to execute in 1 second.
End Sub

第 2 部分 - 需要取消选择的替代方案。

If i = 0 Then
        MsgBox "Nothing to eliminate."
    '--- > Deselect the user selection in uf_assess_sched.uf1_listbox2 < ---
        Exit Sub
End If

【问题讨论】:

  • 您是否尝试过从 0 到 .ListCount-1uf1_listbox3.Selected(i),如果为 True,请将其设置为 False。
  • 感谢帕特里克的回复。非常感谢。在我的 OP 中查看我的更改。我可能误解了您的建议,因为我无法使其发挥作用。
  • 你有这个想法并正确执行它。但是如果没有用户表单的工作流程,我只能建议向 skip control events 添加一个全局布尔变量,比如 bSkipEvents(初始化为 False,group_1 中的 cmdbutton 将其设置为 True),然后在控制事件代码,添加If bSkipEvents Then : bSkipEvents = True : Exit Sub : End If。这应该允许您跳过一次。
  • 再次感谢帕特里克。我感谢在创建解决方案方面付出的额外努力。我想我知道您的最新建议将走向何方。但是,我收到一个错误。请参阅我的 OP 的编辑。我确实冒昧地调整了用户窗体和列表框名称以反映我的需要。我还取出了 userform1.listbox1 点击代码中 textbox1 的引用。我
  • 很抱歉将您与将ListBoxDeSelect() 带出普通模块的想法混淆。我已经编辑了我的解决方案以适应。您也可以跳过Sub ListBox3_DeSelect(),直接使用ListBoxDeSelect uf1_assess_sched.uf1_listbox3 代替错误行。

标签: excel vba deselect


【解决方案1】:

至少有一种方法可以处理无意的用户窗体控件事件。

由于我不知道您的用户窗体如何相互交互,我认为最简单的方法是添加一个 全局布尔变量 以允许您在需要时跳过事件,如下所示。

编辑提示:我已将全局布尔变量 bSkipEventSub ListBoxDeSelect() 取出到普通模块中作为代码缩减,并调用 UserForm1.ListBox1 之类的东西。 (确保该用户窗体中的 ListBox 已显示并启用,否则添加错误捕获代码。

当 UserForms ShowModal = True (TSM) 时,需要一种不同的方法 - Onw 方法是安排调用 Sub 以更改另一个 TSM。在这里,我使用Application.OnTime 在 UserForm2 完全关闭之前将 DelayedListBoxDeSelect 安排为 1 秒。注意 UserFormHelper 中额外的 Public 对象。希望你明白我在这里做什么。

考虑这 2 个简单的用户表单:
 

  1. 加载 UserForm1 并单击 ListBox 选项之一后:
  2. 单击 UserForm2 上的命令按钮会使焦点重新回到 UserForm1:
    请注意 ListBox1 中的虚线选择是如何进行的,我认为最好保留它以提醒之前选择的内容。

代码:
UserForm1

Private Sub UserForm_Initialize()
    bSkipEvent = False
End Sub

Private Sub ListBox1_Click()
    Debug.Print Me.Name, "ListBox1_Click() called"
    If bSkipEvent Then Exit Sub
    With ListBox1
        Debug.Print Me.Name, "ListBox1_Click() ListIndex: " & .ListIndex & " (" & .List(.ListIndex) & ")"
        UserForm2.Show
        UserForm2.TextBox1.Value = .List(.ListIndex) ' This won't have effect if UserForm2 is True on ShowModal
    End With
End Sub

'Sub ListBox1_DeSelect() ' No longer used
'    ListBoxDeSelect Me.ListBox1
'End Sub


UserFormsHelper(普通模块)
Public bSkipEvent As Boolean ' This makes accessible to Userforms and other Modules
Public oListBoxToDeselect As Object '[M2] This is for delayed ListBox Deselect method

' Generic ListBox Deselector
Sub ListBoxDeSelect(oListBox As Object)
    Dim i As Long
    If TypeName(oListBox) <> "ListBox" Then Exit Sub
    bSkipEvent = True
    With oListBox
        For i = 0 To .ListCount - 1
            If .Selected(i) Then
                .Selected(i) = False
            End If
        Next
    End With
    bSkipEvent = False
End Sub

' METHOD 2 [M2] - When UserForm's ShowModal = True
Sub DelayedListBoxDeSelect()
    Dim i As Long
    If TypeName(oListBoxToDeselect) <> "ListBox" Then Exit Sub
    bSkipEvent = True
    With oListBoxToDeselect
        For i = 0 To .ListCount - 1
            If .Selected(i) Then
                .Selected(i) = False
            End If
        Next
    End With
    bSkipEvent = False
    Set oListBoxToDeselect = Nothing
End Sub


UserForm2
Private Sub CommandButton1_Click()
    Debug.Print Me.Name, "CommandButton1_Click() called"
    'UserForm1.ListBox1_DeSelect ' No longer used.
    Set oListBoxToDeselect = UserForm1.ListBox1 ' [M2] This is required for the DelayedListBoxDeSelect(), if top right [X] is clicked, it won't do DeSelect
    Unload Me
End Sub

Private Sub UserForm_Terminate()
    Debug.Print Me.Name, "UserForm_Terminate() called"
    Application.OnTime Now + TimeSerial(0, 0, 1), "DelayedListBoxDeSelect" ' [M2] Sechedules the Sub named "DelayedListBoxDeSelect" to execute in 1 second.
End Sub


调试输出

【讨论】:

  • 帕特里克你还在吗?大声笑我仍然无法使其正常工作。我稍微改变了我的项目,我也遇到了同样的情况,但我的适应似乎不起作用。
  • 很有趣,但为了帮助您在包含控件事件时需要显示大量代码。如果用户表单是 ShowModal = False?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多