ПОЛЬЗОВАТЕЛЬСКАЯ ФОРМА VBA: ПРЕДОТВРАТИТЬ ВЫПОЛНЕНИЕ COMBOBOX НА KEYDOWN

Сообщество,

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

Проблема: в конце списка в поле со списком, если вы нажмете стрелку вниз, вы переместитесь к любому элементу управления, который физически находится под активным полем со списком. И наоборот, если вы находитесь в верхней части выпадающего списка и нажимаете стрелку вверх. Это небрежно и контрпродуктивно. МС Эксель 2013.

Решение. Чтобы предотвратить эту потерю фокуса, в коде ComboBox пользовательской формы вы можете ввести следующее:

Private Sub Item1_DropDown_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

Select Case KeyCode
    Case vbKeyDown
        If Item1_DropDown.ListIndex = Item1_DropDown.ListCount - 1 Then
            Item1_DropDown.ListIndex = Item1_DropDown.ListIndex - 1 'when at the bottom, stay in active combobox
        Else: Item1_DropDown.ListIndex = Item1_DropDown.ListIndex 'if not at the bottom, keep moving down
        End If
    Case vbKeyUp
        If Item1_DropDown.ListIndex = 0 Then 'when at the top, stay in active combobox
            Item1_DropDown.ListIndex = 1
        Else:   Item1_DropDown.ListIndex = Item1_DropDown.ListIndex 'if not at the top, keep moving up
        End If
End Select
      ' where "Item1_DropDown" is the name of my combobox
End Sub

Хорошо, вот как я смог предотвратить переключение поля со списком на другой элемент управления при нажатии вниз / вверх, когда он находится внизу / вверху списка ComboBox.

Кто-нибудь знает более чистый способ сделать это? Может быть, способ сделать это без использования кода?


person Elias    schedule 11.07.2013    source источник
comment
Помимо того, что для этого требуется код (поэтому код необходимо копировать в каждое новое раскрывающееся меню), есть ли у вашего решения какой-либо недостаток? Если нет, то лучше будет сложно найти :-)   -  person d-stroyer    schedule 11.07.2013
comment
Нет. Пока все работает нормально. Во время тестирования моего проекта я использовал пользовательскую форму около 200 раз без сучка и задоринки. Кстати, я также добавил третье предложение Case. Он обрабатывает кнопку «Удалить».   -  person Elias    schedule 11.07.2013


Ответы (3)


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

Private Sub Item1_DropDown_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

Select Case KeyCode
    Case vbKeyDown
        If Item1_DropDown.ListIndex = Item1_DropDown.ListCount - 1 Then KeyCode = 0
    Case vbKeyUp
        If Item1_DropDown.ListIndex = 0 Then KeyCode = 0
End Select
      ' where "Item1_DropDown" is the name of my combobox
End Sub

вы можете использовать класс, если вам часто нужен этот код

person JosieP    schedule 11.07.2013
comment
Спасибо. Этот код тоже работает. Я не знаю, почему это работает, но это работает. - person Elias; 11.07.2013
comment
это в основном отменяет нажатие клавиши - person JosieP; 11.07.2013

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

По сути, за этим стоит усовершенствованное использование решений, показанных выше. Вот оно:

ШАГ № 1: Создайте модуль класса

'clsTask      (this is the 'name' of your Class Module | the name is important!)
Public WithEvents cBox as MSForms.ComboBox    'create a property for your class/object


Public Sub cBox_KeyDown(ByVal KeyCode as MSForms.ReturnInteger, ByVal shift as Integer)

    Select Case KeyCode
        Case vbKeyDown
            if cBox.ListIndex = cBox.ListCount - 1 Then KeyCode = 0
        Case vbKeyUp
            if cBox.ListIndex = 0 Then KeyCode = 0
        Case vbKeyEnd
            cBox.ListIndex = cBox.ListCount - 1
        Case vbKeyHome
            cBox.ListIndex = 0
        Case 46
            cBox.Value = ""
    End Select
'this is just the code from above
End Sub

Шаг № 2: Объявить сбор

'in a standard module            (for Excel 2013, you might need to declare this in a standard module; otherwise, anywhere else may suffice)

Public BoxColl as Collection

Шаг № 3: Инициализируйте форму пользователя

 '(initialize all desired ComboBoxes in your Userform to use Trap Code (step 1 above))

'userform code

Private Sub Userform_Initialize()

    Dim ctl as Control, ox as clsTask
    Set BoxColl = New Collection
    For Each ctl in Me.Controls
        If TypeOf ctl is MSForms.Label Then            'you could also include an identifying tag here
            Set ox = New clsTask
            Set ox.cBox = ctl
            BoxColl.Add ox
        End if
    Next
'this piece of code sets all of your comboboxes as your defined object/class.
'then it puts each combobox into a collection
'all items in the collection will get the Double Click Event treatment on cue
End Sub

Хорошо, это все. Это полезно, если у вас есть несколько ComboBox в пользовательской форме, к которым вы хотите применить один и тот же код. В этом случае, если вы хотите захватить кнопки вверх и вниз в конце списка, этот код будет работать для каждого отдельного поля со списком.

Имейте в виду, что если вы хотите, чтобы только определенные поля со списком имели эту функциональность, вам нужно будет добавить тег к тем, которые вы хотите. Затем в инициализации пользовательской формы в предложении «For...Each» вам нужно будет добавить условное предложение этого тега в операторе «if».

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

Удачи!

person Community    schedule 21.07.2013

Я попробовал это последнее предложение, и оно отлично сработало после того, как я заменил «MSForms.Label» на «MSForms.ComboBox».

person Johnny Rosenberg    schedule 15.11.2017