【问题标题】:WorksheetChange Event to Concatenate Row and First Letter of First Name + First Letter of Last NameWorksheetChange 事件以连接行和名字的第一个字母 + 姓氏的第一个字母
【发布时间】:2017-03-27 23:29:31
【问题描述】:

我认为代码应该是这样的,但我在尝试处理名字和姓氏的这一行遇到错误。基本上,我想在 A 列中创建一个代码,它是人名的第一个字母和人的姓氏的第一个字母,与行号连接。该行将是活动行(始终为 A 列),名字和姓氏将存储在 B 列中。

Private Sub Worksheet_Change(ByVal Target As Range)

  If Target.Column <> 1 Then Exit Sub

  On Error GoTo ErrHandler
  Application.EnableEvents = False
    If Target.Column = 1 Then
        Target.Offset(0, 0).FormulaR1C1 = "=ROW()"
        TV1 = Target.Offset(0, 0).FormulaR1C1
        Target.Offset(0, 0).FormulaR1C1 = "=UPPER(LEFT(R[" & "=ROW()" & "]C[1],1)&MID(R[" & "=ROW()" & "]C[1],FIND("" "",R[" & "=ROW()" & "]C[1],1)+1,1))"
        TV2 = Target.Offset(0, 0).FormulaR1C1
        Target.Offset(0, 0).Value = TV2 & "-" & TV1
    End If

End Sub

【问题讨论】:

  • R[" &amp; "=ROW()" &amp; "] 可以写成R,如果你只想要同一行而不是偏移等于同一行的行数。

标签: excel vba


【解决方案1】:

我不想避免将多个单元格作为目标处理。处理多个单元格并不难。

在禁用事件并执行处理后,您不会再次将它们重新打开。您的代码只会运行一次,无需手动重新开启事件。

如果您将名字和姓氏放入 B 列,那么处理是否应该受制于 B 列而不是 A 列?

Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)

    If Not Intersect(Target, Columns("B")) Is Nothing Then
        On Error GoTo ErrHandler
        Application.EnableEvents = False
        Dim trgt As Range
        For Each trgt In Intersect(Target, Target.Parent.UsedRange, Columns("B"))
            trgt = StrConv(Trim(trgt.Value2), vbProperCase)
            If CBool(InStr(2, trgt.Value2, Chr(32))) Then
                trgt.Offset(0, -1) = _
                    UCase(Left(trgt.Value2, 1)) & _
                    UCase(Mid(trgt.Value2, InStr(1, trgt.Value2, Chr(32)) + 1, 1)) & _
                    Format(trgt.Row, "000")
            End If
        Next trgt
    End If

ErrHandler:
  Application.EnableEvents = True
End Sub

我添加了一些修剪和适当大小写转换,以自动更正输入到 B 列中的值。

在下图中,我从 G5:G8 中复制了名称并将它们粘贴到 B2:B5 中。

【讨论】:

    【解决方案2】:

    我会以不同的方式做这件事。既然可以在 VBA 中简单地编写公式,为什么还要编写公式?

    我还对您的原始代码做了一些注释:


    Option Explicit
    
    Private Sub Worksheet_Change(ByVal Target As Range)
    
      If Target.Column <> 1 Then Exit Sub
    
      Application.EnableEvents = False
    
    ' No error handler in your code
    'On Error GoTo ErrHandler
    
    ' don't need to check if column 1 since we already did that and exited the sub if it was not
    '    If Target.Column = 1 Then
    
            'Target.Offset(0,0) = Target
            'Target.Offset(0, 0).FormulaR1C1 = "=ROW()"
            'TV1 = Target.Offset(0, 0).FormulaR1C1
            'Target.Offset(0, 0).FormulaR1C1 = "=UPPER(LEFT(R[" & "=ROW()" & "]C[1],1)&MID(R[" & "=ROW()" & "]C[1],FIND("" "",R[" & "=ROW()" & "]C[1],1)+1,1))"
            'TV2 = Target.Offset(0, 0).FormulaR1C1
            'Target.Offset(0, 0).Value = TV2 & "-" & TV1
    
            'Just do the creation in VB
            With Target
                .Value = .Row & Left(.Offset(0, 1), 1) & Left(Split(.Offset(0, 1))(1), 1)
            End With
    
            'If you have more than two space-separated words in the name, then something like
            Dim V As Variant
            With Target
                V = Split(.Offset(0, 1))
                .Value = .Row & Left(V(0), 1) & Left(V(UBound(V)), 1)
            End With
    
    'Don't forget to reenable events
    Application.EnableEvents = True
    
    
    End Sub
    

    另外,既然名称在 B 列中,为什么要测试 A 列中的更改?可能有原因,但如果没有,检查 B 列中的更改可能会更顺畅。

    【讨论】:

    • 是的,现在一切都说得通了。感谢您的关注!
    【解决方案3】:

    我想通了!!

    If Target.Column = 1 Then
        Target.Offset(0, 0).FormulaR1C1 = "=ROW()"
        TV1 = Target.Value
        Target.Offset(0, 0).FormulaR1C1 = "=UPPER(LEFT(RC[1],1)&MID(RC[1],FIND("" "",RC[1],1)+1,1))"
        TV2 = Target.Value
        Target.Value = TV2 & "-" & TV1
    End If
    

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 2020-10-15
      • 2021-05-05
      • 1970-01-01
      • 2017-04-17
      • 2022-11-04
      相关资源
      最近更新 更多