使用Control +箭头键[Excel]从ComboBox失去焦点

时间:2019-01-06 15:45:27

标签: excel vba combobox

我正在设置一个工作表,其中包含一个VBA代码,该代码将ComboBox放置在我要使用Datavalidation的任何单元格中。

每当我转到使用datavalidation的单元格时,它将启用ComboBox并将ComboBox移至我选择的单元格。当我选择一个新的单元格时,它将ComboBox移到新位置,或者如果该单元格不包含DataValidation,它就会被隐藏起来。

问题是我有大约1000行和2列,我很容易浏览它们,所有这些都将输入我用于数据验证的任何列表选项。因此,我希望能够使用鼠标在行之间上下左右导航,而无需使用鼠标。

现在我无法做到这一点。当我转到ComboBox时,它会自动让我键入它,如果我再继续按箭头键,我会滚动浏览我的ComboBox列表。

我已成功添加了一个代码,该代码可让我按Enter向下移动,然后按Tab键向右移动,但是如果我将按钮更改为一个箭头键,并且无法确定如何进行编辑,那么就可以正常工作了或离开。没有该代码,我只能使用“退出”或单击鼠标来使该单元格失去焦点。

我更喜欢的解决方案是在代码中的某处添加if语句,该语句要求我保留Control或在不激活代码的情况下四处移动。例如

激活组合框代码  如果未按下控制键  如果当前单元格包含Datavalidation。

这是我正在使用的代码。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Update by Extendoffice: 2018/9/21
    Dim xCombox As OLEObject
    Dim xStr As String
    Dim xWs As Worksheet
    Dim xArr

    Set xWs = Application.ActiveSheet
    On Error Resume Next
    Set xCombox = xWs.OLEObjects("TempCombo")
    With xCombox
        .ListFillRange = ""
        .LinkedCell = ""
        .Visible = False
    End With
    If Target.Validation.Type = 3 Then
        Target.Validation.InCellDropdown = False
        Cancel = True
        xStr = Target.Validation.Formula1
        xStr = Right(xStr, Len(xStr) - 1)
        If xStr = "" Then Exit Sub
        With xCombox
            .Visible = True
            .Left = Target.Left
            .Top = Target.Top
            .Width = Target.Width + 5
            .Height = Target.Height + 5
            .ListFillRange = xStr
            If .ListFillRange = "" Then
                xArr = Split(xStr, ",")
                Me.TempCombo.List = xArr
            End If
            .LinkedCell = Target.Address
        End With
        xCombox.Activate

    End If
End Sub
Private Sub TempCombo_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Select Case KeyCode
        Case 9
            Application.ActiveCell.Offset(0, 1).Activate
        Case 13
            Application.ActiveCell.Offset(1, 0).Activate
    End Select
End Sub

1 个答案:

答案 0 :(得分:0)

首先,好的代码。

第二,在KeyDown方法中尝试以下操作:

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

    Dim celltemp(1) As String

    Select Case KeyCode

        Case 38
            celltemp(0) = Application.ActiveCell.Cells(0, 1).Address
            celltemp(1) = CStr(Application.ActiveCell.Cells(0, 1).Value)

        Case 40
            celltemp(0) = Application.ActiveCell.Cells(2, 1).Address
            celltemp(1) = CStr(Application.ActiveCell.Cells(2, 1).Value)

        Case 39
            celltemp(0) = Application.ActiveCell.Cells(1, 2).Address
            celltemp(1) = CStr(Application.ActiveCell.Cells(1, 2).Value)

        Case 37
            celltemp(0) = Application.ActiveCell.Cells(1, 0).Address
            celltemp(1) = CStr(Application.ActiveCell.Cells(1, 0).Value)

    End Select

    TempCombo.Enabled = False

    ActiveSheet.Range(celltemp(0)).Activate

    If CStr(ActiveCell.Value) <> celltemp(1) Then _
    ActiveCell.Value = celltemp(1)

    TempCombo.Enabled = True

End Sub

我认为它具有预期的行为。

如您所见,在我的键盘上,箭头的KeyCodes从37到40。我不确定在所有键盘上它是否都相同,但是您可以简单地对其进行修改以使其起作用。如果它们与我的代码不同,请在Select Case语句之前使用以下代码来获取代码:

debug.print KeyCode

如果只希望在按下控制键时执行该操作,则有一种方法:使用虚拟键,并在KeyDown方法中包括一个迭代,该迭代允许仅在按下键时执行其余代码想要(在这种情况下:控制键)。

这是我做到的方式(我在此处包括完整的代码):

'declare virtual key event listener ---------------------------------------

#If VBA7 Then
    Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" _
            (ByVal vKey As Long) As Integer
#Else
    Private Declare Function GetAsyncKeyState Lib "user32" _
            (ByVal vKey As Long) As Integer
#End If
'--------------------------------------------------------------------------

'declare virtual key constants -------------------------------------------

Private SWITCH As Boolean

Private Const VK_CTRL = &H11 'CONTROL key
Private Const VK_LEFT = &H25 'LEFT ARROW key
Private Const VK_UP = &H26 'UP ARROW key
Private Const VK_RIGHT = &H27 'RIGHT ARROW key
Private Const VK_DOWN = &H28 'DOWN ARROW key
'--------------------------------------------------------------------------

'For more information about virtual key interactions with VBA visit the following link:
'    https://wellsr.com/vba/2017/excel/GetAsyncKeyState-vba-to-wait-until-a-key-is-pressed/


Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    Dim xCombox As OLEObject
    Dim xStr As String
    Dim xWs As Worksheet
    Dim xArr

    Set xWs = Application.ActiveSheet
    On Error Resume Next
    Set xCombox = xWs.OLEObjects("TempCombo")

    With xCombox

        .ListFillRange = ""
        .LinkedCell = ""
        .Visible = False

    End With

    If Target.Validation.Type = 3 Then

        Target.Validation.InCellDropdown = False
        Cancel = True
        xStr = Target.Validation.Formula1
        xStr = RIGHT(xStr, Len(xStr) - 1)
        If xStr = "" Then Exit Sub

        With xCombox

            .Visible = True

            If Not SWITCH Then

                .LEFT = Target.LEFT
                .Top = Target.Top

            End If

            .Width = Target.Width + 5
            .Height = Target.Height + 5
            .ListFillRange = xStr

            If .ListFillRange = "" Then

                xArr = Split(xStr, ",")
                Me.TempCombo.List = xArr

            End If

            .LinkedCell = Target.Address

        End With

        xCombox.Activate

    End If

End Sub


Private Sub TempCombo_KeyDown(ByVal keycode As MSForms.ReturnInteger, ByVal Shift As Integer)

    If Not SWITCH Then

        Do While GetAsyncKeyState(VK_CTRL) <> 0

            If GetAsyncKeyState(VK_LEFT) Then
                ActiveSheet.Range(Application.ActiveCell.Cells(1, 0).Address).Activate
                Exit Do

            ElseIf GetAsyncKeyState(VK_RIGHT) Then
                ActiveSheet.Range(Application.ActiveCell.Cells(1, 2).Address).Activate
                Exit Do

            ElseIf GetAsyncKeyState(VK_UP) Then
                ActiveSheet.Range(Application.ActiveCell.Cells(0, 1).Address).Activate
                Exit Do

            ElseIf GetAsyncKeyState(VK_DOWN) Then
                ActiveSheet.Range(Application.ActiveCell.Cells(2, 1).Address).Activate
                Exit Do

            End If

        Loop

    Else

        SWITCH = False

    End If

    If keycode = 17 Then SWITCH = True

End Sub

您可以在此处下载完整文件:Key-controlled ActiveX comboboxes--test--(GitHub)

问候