【问题标题】:Comparing two Sheet objects (not contents)比较两个工作表对象(不是内容)
【发布时间】:2015-01-06 23:38:28
【问题描述】:

在错误处理代码的上下文中,我想验证用户是否在同一工作簿中为当前工作表赋予了另一个工作表的相同名称(当然禁止操作)。因此,我直观地尝试验证这一点的方式是简单地遍历所有工作表并比较名称:

For Each sh In ThisWorkbook.Sheets
    If sh.Name = ThisWorkbook.ActiveSheet.Name Then
        'error handling here
    End If
Next sh

但是,在以下情况下这是一个巨大的逻辑错误:

1) 用户正在编辑,比方说,工作表编号 3; 2)同名的sheet在位置5;

在这种情况下,肯定会满足条件sh.Name = ThisWorkbook.ActiveSheet.Name,因为工作表会与自身进行比较。

所以,我想知道:如何理解sh 不是ThisWorkbook.ActiveSheet

我认为这个任务可以通过简单的对象比较来解决:

If (sh Is Not ThisWorkbook.ActiveSheet) And (sh.Name = ThisWorkbook.ActiveSheet.Name) Then

但这会引发编译错误,即对象不支持此属性或方法。谁能帮我找到我的代码结构中缺乏逻辑的地方?

其他信息

我尝试通过Err.DescriptionErr.Number 来管理此案例,但第一个是依赖于操作系统语言的,第二个对于我需要以不同方式处理的其他类型的错误是相同的。

此外,工作表(名称和内容)包含在.xlam 加载项中,因此用户可以通过自定义用户表单而不是通过 Excel 应用程序更改内容。

更一般地说,假设我想知道如何进行比较,即使在这种特定情况下可以解决,以便将这种方法用于我已经计划做的未来开发和无法通过默认的 VBA 错误处理程序进行管理。

【问题讨论】:

  • 用户是在 VBA 代码中还是通过手动输入给“另一个工作表相同的名称”?因为手动输入会给您一个错误:“该工作表名称已被使用。请输入另一个工作表未使用的工作表名称。”
  • @Christmas007,该名称是通过用户窗体上的文本框输入的,并将其自身更新为TextBox_Change 事件。我已经尝试通过Err.Description 进行管理,但是该消息被提升为操作系统语言,这会导致跨语言问题。也通过错误代码进行了尝试,但它与必须以不同方式管理的其他情况相同。此外,我只想知道如何正确比较这两个对象,因为当没有引发特定错误时,我会进一步需要它。
  • @GeneSkuratovsky 请阅读我上面的评论,以便更好地理解上下文。工作表包含在加载项中,因此用户可以通过用户表单更改工作表的名称和内容,而不会在桌面上看到工作表。这就是(不幸的是)我需要构建自定义错误处理程序的原因:(
  • @GeneSkuratovsky 没问题,感谢您的反馈! :)
  • 刚刚意识到您的逻辑中有一个错误:“用户正在编辑,比如说,工作表编号 3;2) 同名工作表 位于位置编号 5" 不可能创建两个或多个具有相同名称的工作表。

标签: vba


【解决方案1】:

只需检查工作表的索引和名称即可。 如果名称匹配,则只有错误(或其他),但索引不匹配。

Option Explicit

Public Sub test()
    Dim wb As Workbook
    Dim ws As Worksheet

    Set wb = ThisWorkbook
    Set ws = wb.ActiveSheet

    Dim wsToCheck As Worksheet
    For Each wsToCheck In wb.Worksheets
        If ws.Name = wsToCheck.Name And ws.Index <> wsToCheck.Index Then
            'do something
        End If
    Next
End Sub

当然,您也可以只使用test for object equality using the Is operator,或者在您的具体情况下不等式。

Public Sub test2()
    Dim wb As Workbook
    Dim ws As Worksheet

    Set wb = ThisWorkbook
    Set ws = wb.ActiveSheet

    Dim wsToCheck As Worksheet
    For Each wsToCheck In wb.Worksheets
        If Not ws Is wsToCheck Then
            'do something
            Debug.Print ws.Name
        End If
    Next
End Sub

【讨论】:

  • 非常聪明的举动,不能否认赞成票。但是,我仍然想知道是否可以执行实例比较。我的意思是shThisWorkbook.ActiveSheet 可能会变成同一个对象实例。如果我们不知道如何执行我要求的比较,我最近会接受这个答案。非常感谢您的宝贵时间:)
  • 好吧,原来这只是一个愚蠢的语法错误,我写的是sh Is Not而不是Not sh Is。我已建议此编辑并接受您的回答,因为它完全回答了我的问题!
  • 我赞成您对第二个(优秀)答案的回答。但是,如果我们有两个相同的工作簿并且查询的工作表是这两个工作簿中的相应工作表(它们将具有相同的名称和索引,后面有不同的工作簿),第一部分可能会失败。跨度>
【解决方案2】:

“Not”的语法不正确;应该是这样的:

If (Not sh Is ThisWorkbook.ActiveSheet) And (sh.Name = ThisWorkbook.ActiveSheet.Name) Then

【讨论】:

  • 再次,我迟到了几秒钟:(
  • 谢谢 Gene,刚刚意识到!为了公平起见,我继续接受 RubberDuck 的回答,但非常感谢您的帮助,+1 !!!
  • @GeneSkuratovsky 它赢得了我的支持,但我觉得很高兴支持您认为值得花时间回答的问题。我的意思是,如果值得回答,难道不值得点赞吗?
  • @RubberDuck,完全同意,这是我们奖励用户为我们付出的时间的方式;)
  • @GeneSkuratovsky,我想叫你:鹰眼!
【解决方案3】:

没有理由遍历工作表集合。使用这个:

Function IsWshExists(ByVal wbk As Workbook, ByVal wshName As String) As Boolean
Dim wsh As Worksheet

On Error Resume Next
Set wsh = wbk.Worksheets(wshName)

IsWshExists = (Err.Number = 0)

Set wsh = Nothing
End Function

用法:

If Not IsWshExists(ThisWorkbook, "Sheet2") Then 
    'you can add worksheet ;)
    'your logic here
End If

【讨论】:

  • 它可以工作,但是依赖错误处理程序并恢复下一个是非常糟糕的。
  • 嗯,这个其实有点欠缺。如果我传递一个空字符串作为名称,该函数会告诉我工作表存在,而这不是真的,不是吗?
  • Maceej Los 的一般错误处理方法是可以的 - 但你应该测试 If Not wsh is Nothing 等,Matteo NNZ 提出了一个公平的观点,因为你运行它的方式
  • @Chrismas007 在这种情况下他实际上不需要,但是是的。你所说的是一般的最佳实践。
  • @MaciejLos,我非常感谢您的时间,您的时间实际上是解决许多问题的好方法。我的意思是,在我的上下文中,我需要知道是否存在另一张同名的工作表。在这种情况下,您的函数可以正常工作,但即使我传递无效名称(例如空字符串或包含 *、: 等特殊字符的字符串),它也会产生相同的结果(即 Existing)。你明白我的意思? :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 2021-08-05
  • 1970-01-01
相关资源
最近更新 更多