Excel VBA - Как отменить выбор ранее выбранного элемента в списке

У меня есть пользовательская форма (uf1_assess_sched) в моем проекте Excel VBA, который имеет список (uf1_listbox3).

Когда пользователь выбирает один элемент в этом списке, открывается вторая пользовательская форма (группа_1), позволяющая пользователю вводить информацию, специфичную для выбора, который он сделал в первой пользовательской форме. Если пользователь желает отказаться от дальнейшей записи в group_1, он может выйти, нажав кнопку команды под названием Выход.

После выхода group_1 выгружается, и uf1_assess_sched выходит на передний план. Идея состоит в том, чтобы позволить пользователю выбрать другой элемент из uf1) listbox3. Тем не менее, выбор, который она первоначально сделала, все еще выбран.

Как отменить выбор этого ранее сделанного выбора.

Я пытался:

With uf1_assess_sched
    .uf1_listbox3.listindex = -1
End With

Это наиболее актуально, что я мог найти в любом из моих поисков.

Следуя совету Патрика, с моим ограниченным пониманием 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.

Я надеюсь, что предоставлю отзыв соответствующим образом, просто отредактировав свой оригинальный пост. Я не уверен, как добавить код в комментарий. Stackru - это новый формат для меня, поэтому я делаю все возможное.

С последним кодом, любезно предоставленным Патриком, мне удалось пройти так далеко, прежде чем я столкнулся с ошибкой. Я сделал некоторые изменения, чтобы отразить имя пользователя и список. Я получаю сообщение об ошибке "Метод или элемент данных не найден. " С кодом во второй пользовательской форме, 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

Я поместил подпрограммы 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

Вот мой последний код (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 (выход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
        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

1 ответ

Решение

Существует как минимум один способ справиться с непреднамеренными событиями элементов управления UserForm.

Поскольку я не знаю, как ваши пользовательские формы взаимодействуют друг с другом, я считаю, что проще всего добавить глобальную логическую переменную, чтобы при необходимости пропустить событие, как показано ниже.

Отредактированный совет: я вынул глобальную логическую переменную bSkipEvent а также Sub ListBoxDeSelect() к нормальному модулю как сокращение кода, и вызывает, чтобы добавить такие вещи, как UserForm1.ListBox1, (Убедитесь, что ListBox в этой пользовательской форме показан и включен, в противном случае добавьте код перехвата ошибок).

Когда пользовательские формы ShowModal = True (TSM), требуется другой подход. Один из способов заключается в том, чтобы запланировать вызов Sub для изменения другого TSM. Здесь я использовал Application.OnTime запланировать DelayedListBoxDeSelect за 1 секунду до того, как UserForm2 будет полностью закрыт. Обратите внимание на дополнительный объект Public в UserFormHelper. Надеюсь, вы понимаете, что я здесь делаю.

Рассмотрим эти 2 простые пользовательские формы:
UserForm1_Design UserForm2_Design

  1. После загрузки UserForm1 и щелкнул один из вариантов ListBox:
    UserForm1_ListBox_Click
  2. Нажатие на кнопку "Command" на UserForm2 возвращает фокус на UserForm1:
    Обратите внимание, как пунктирная выделение в ListBox1, я думаю, что это хорошо, чтобы оставить это как напоминание о том, что было выбрано ранее.
    UserForm2_Cmd_Clicked

коды:
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


Отладочный вывод
DebugOutput

Другие вопросы по тегам