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 и щелкнул один из вариантов ListBox:
- Нажатие на кнопку "Command" на 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
Отладочный вывод