在工作表名称中包含字符串和单元格值

Mik*_*ike 0 excel vba excel-vba

我有一个简单的工作簿,有3个不同的网站,我可以从中购买东西.我想在编辑工作表时更新选项卡名称.工作表名称将是网站名称+所有项目的总和(单元格C27)

这是我拥有的宏:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Range("B27")) Is Nothing Then
        ActiveSheet.Name = "Amazon " + ActiveSheet.Range("B27")
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

我得到运行时错误'13':类型不匹配

我知道这是因为我将2种不同类型的字符串和值组合在一起,但我不太熟悉VBA的语法以便能够修复它.

如果我省略网站名称,它就完美无缺.

什么是最容易解决的问题?

Mat*_*don 5

ActiveSheet.Name = "Amazon " + ActiveSheet.Range("B27")
Run Code Online (Sandbox Code Playgroud)

ActiveSheet.Name是一个String."Amazon"字面意思也是如此.我假设单元格$B$27ActiveSheet包含一个数值; 该+运营商作为除了运营商,VBA抛出一个类型不匹配,因为它不知道如何添加一个字符串的数字,你可以在轻松重现立即窗格(按Ctrl + G):

?"foo" + 42
'type mismatch
Run Code Online (Sandbox Code Playgroud)

+字符串连接运算符替换运算符&可修复症状,并"正常":

?"foo" & 42
'foo42
Run Code Online (Sandbox Code Playgroud)

但是,您需要考虑实际发生的事情,并解决问题,而不仅仅是症状:当您使用字符串连接运算符时,VBA会隐式地将所有操作数转换为字符串.您可以使用以下CStr函数显式转换:

?"foo" & CStr(42)
'foo42, this time without implicit conversions
Run Code Online (Sandbox Code Playgroud)

但是ActiveSheet.Range("B27")是一个对象 - 一个Range对象引用:

?TypeName(ActiveSheet.Range("B27"))
Range
Run Code Online (Sandbox Code Playgroud)

这里还有另一个隐式操作:它不是你要转换为字符串的对象引用(隐式或显式),它是默认成员的值.如果你Range对象浏览器(F2)中查看对象,你会发现它有一个隐藏的_Default属性:

VBE对象浏览器中的范围.[_ Default]

该默认属性显然是以它获取/设置的方式实现的Range.Value; 这就是为什么这段代码编译:

ActiveSheet.Range("B27") = 42
Run Code Online (Sandbox Code Playgroud)

这段代码也是如此:

Dim foo As Long
foo = ActiveSheet.Range("B27")
Run Code Online (Sandbox Code Playgroud)

如果没有默认成员隐式"重定向"调用Value,这些将是非法的,因为您不能在不使用Set关键字的情况下分配对象引用,也不能将对象引用分配给值.

注意Range("B27")这里的区别:

If Not Intersect(Target, Range("B27")) Is Nothing Then
Run Code Online (Sandbox Code Playgroud)

这里对比:

ActiveSheet.Name = "Amazon " + ActiveSheet.Range("B27")
Run Code Online (Sandbox Code Playgroud)

前者是Range对象,后者是它Value.还要注意Range("B27")隐含地引用了ActiveSheet,所以这个:

Range("B27")
Run Code Online (Sandbox Code Playgroud)

与此完全相同:

ActiveSheet.Range("B27")
Run Code Online (Sandbox Code Playgroud)

没有理由不在ActiveSheet任何地方明确限定它.实际上,只要查看标记中的任何随机100 Stack Overflow问题,Range使用Worksheet对象限定所有调用就可以为您节省很多问题.

因此,编写处理程序的显式方法如下 - 请注意,有效的工作表名称必须为32个字符或更少,因此如果连接的字符串长于此字符,则需要截断名称.由于两个工作表不能具有相同的名称,因此如果截断的字符串导致工作簿中已存在工作表名称,则需要执行某些操作:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, ActiveSheet.Range("B27")) Is Nothing Then
        On Error Resume Next
        ActiveSheet.Name = Left$("Amazon " & CStr(ActiveSheet.Range("B27").Value), 32)
        On Error GoTo 0
        If Err.Number <> 0 Then MsgBox "Could not rename worksheet '" & ActiveSheet.Name & "'."
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

在这一点上,无论你使用的&+运算符还是运算符都没关系,因为+运算符可以很好地连接字符串...当所有操作数都是字符串时 - 除了一致性和可读性之外,你肯定希望更喜欢使用&运算符连接字符串时.