代码之家  ›  专栏  ›  技术社区  ›  RonanC

VBA数据验证下拉列表,是否也允许自由文本?

  •  0
  • RonanC  · 技术社区  · 1 年前

    我在网上其他地方找到了一段代码,允许从“数据验证”选项中生成的列表中进行多项选择。它工作得很好,在我正在进行的数据收集练习中应该真的很有帮助。我想通过允许大量的选择来加快最终用户的工作,让这个过程对最终用户来说是无痛的。

    然而,我想知道是否可以对其进行更改,以允许用户也输入免费文本。另一个显而易见的问题是,有一行代码,当单元格值发生变化时(例如有人键入自由文本),新值会附加到现有值上。这会导致单元格重复其内容,即使只是点击“返回”等

    代码示例“Destination.Value=oldValue&DelimiterType&newValue”

    该事件是在修改单元格的内容后触发的。当输入自由文本时,Excel将其视为修改并触发“Worksheet_Change”事件。此时,oldValue是以前选择的项目的整个列表,newValue是刚刚输入的自由文本。代码将这些连接在一起,导致重复。

    所以我的问题是,是否有一种方法可以允许自由文本输入,而不会造成重复效果。非常感谢。

    代码如下:

    Private Sub Worksheet_Change(ByVal Destination As Range)
    Dim rngDropdown As Range
    Dim oldValue As String
    Dim newValue As String
    Dim DelimiterType As String
    DelimiterType = vbCrLf
    Dim DelimiterCount As Integer
    Dim TargetType As Integer
    Dim i As Integer
    Dim arr() As String
     
    If Destination.Count > 1 Then Exit Sub
    On Error Resume Next
     
    Set rngDropdown = Cells.SpecialCells(xlCellTypeAllValidation)
    On Error GoTo exitError
     
    If rngDropdown Is Nothing Then GoTo exitError
     
    TargetType = 0
        TargetType = Destination.Validation.Type
        If TargetType = 3 Then  ' is validation type is "list"
            Application.ScreenUpdating = False
            Application.EnableEvents = False
            newValue = Destination.Value
            Application.Undo
            oldValue = Destination.Value
            Destination.Value = newValue
            If oldValue <> "" Then
                If newValue <> "" Then
                    If oldValue = newValue Or oldValue = newValue & Replace(DelimiterType, " ", "") Or oldValue = newValue & DelimiterType Then ' leave the value if there is only one in the list
                        oldValue = Replace(oldValue, DelimiterType, "")
                        oldValue = Replace(oldValue, Replace(DelimiterType, " ", ""), "")
                        Destination.Value = oldValue
                    ElseIf InStr(1, oldValue, DelimiterType & newValue) Or InStr(1, oldValue, " " & newValue & DelimiterType) Then
                        arr = Split(oldValue, DelimiterType)
                    If Not IsError(Application.Match(newValue, arr, 0)) = 0 Then
                        Destination.Value = oldValue & DelimiterType & newValue
                            Else:
                        Destination.Value = ""
                        For i = 0 To UBound(arr)
                        If arr(i) <> newValue Then
                            Destination.Value = Destination.Value & arr(i) & DelimiterType
                        End If
                        Next i
                    Destination.Value = Left(Destination.Value, Len(Destination.Value) - Len(DelimiterType))
                    End If
                    ElseIf InStr(1, oldValue, newValue & Replace(DelimiterType, " ", "")) Then
                        oldValue = Replace(oldValue, newValue, "")
                        Destination.Value = oldValue
                    Else
                        Destination.Value = oldValue & DelimiterType & newValue
                    End If
                    Destination.Value = Replace(Destination.Value, Replace(DelimiterType, " ", "") & Replace(DelimiterType, " ", ""), Replace(DelimiterType, " ", "")) ' remove extra commas and spaces
                    Destination.Value = Replace(Destination.Value, DelimiterType & Replace(DelimiterType, " ", ""), Replace(DelimiterType, " ", ""))
                    If Destination.Value <> "" Then
                        If Right(Destination.Value, 2) = DelimiterType Then  ' remove delimiter at the end
                            Destination.Value = Left(Destination.Value, Len(Destination.Value) - 2)
                        End If
                    End If
                    If InStr(1, Destination.Value, DelimiterType) = 1 Then ' remove delimiter as first characters
                        Destination.Value = Replace(Destination.Value, DelimiterType, "", 1, 1)
                    End If
                    If InStr(1, Destination.Value, Replace(DelimiterType, " ", "")) = 1 Then
                        Destination.Value = Replace(Destination.Value, Replace(DelimiterType, " ", ""), "", 1, 1)
                    End If
                    DelimiterCount = 0
                    For i = 1 To Len(Destination.Value)
                        If InStr(i, Destination.Value, Replace(DelimiterType, " ", "")) Then
                            DelimiterCount = DelimiterCount + 1
                        End If
                    Next i
                    If DelimiterCount = 1 Then ' remove delimiter if last character
                        Destination.Value = Replace(Destination.Value, DelimiterType, "")
                        Destination.Value = Replace(Destination.Value, Replace(DelimiterType, " ", ""), "")
                    End If
                End If
            End If
            Application.EnableEvents = True
            Application.ScreenUpdating = True
        End If
     
    exitError:
      Application.EnableEvents = True
    End Sub
     
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)```
    
    0 回复  |  直到 1 年前
        1
  •  0
  •   ΑΓΡΙΑ ΠΕΣΤΡΟΦΑ    1 年前

    图中显示了当您希望编写内容而不重复现有值时要采取的步骤。关键点是在键入之前选择内容。。。键入时,旧文本将消失,但按ENTER键时将重新出现。

    enter image description here