【问题标题】:Prevent user from deleting a particular sheet防止用户删除特定工作表
【发布时间】:2022-03-12 18:57:07
【问题描述】:

保护工作簿结构将阻止用户删除工作表。但是我如何(使用 VBA)阻止用户删除我指定的 特定 工作表?我已经看到了阻止删除活动工作表的示例

Set mymenubar = CommandBars.ActiveMenuBar
mymenubar.Controls("Edit").Controls("Delete sheet").Visible = False

在其Worksheet_Activate 事件中,但当然只有在工作表被激活时才有效。
有没有办法防止工作表被删除,无论是否处于活动状态?
为了清楚起见:我同意用户删除一些工作表,而不是几个特定的​​工作表。
所以保护工作簿结构是行不通的。

【问题讨论】:

  • 为什么不使用隐藏?你知道你可以隐藏床单吗?您也可以将它们锁定。
  • 我需要用户查看这些工作表,但不要删除它们。它们是数据输入表,充满了工作表激活事件。删除它们会很痛苦。
  • 我不知道是否有助于注意从 UI 中删除工作表的唯一方法而不首先激活它是选择多个工作表?

标签: vba excel


【解决方案1】:

据我所知,不可能将单个工作表本地标记为不可删除;并且没有可用于检测何时将要删除工作表的事件,因此可以预防性地保护工作簿。

但是,这是一种可能的解决方法:

  1. 保护工作簿结构:正如您所指出的,这将防止所有工作表被删除。
  2. 创建一个“控件”表。在此工作表上,维护所有工作表名称的列表(您不想删除的除外)。
  3. 如果用户想要删除工作表,他们必须在“控制”工作表上选择其名称(例如在数据验证下拉菜单中),然后按“删除”按钮。此按钮将调用一个宏,该宏会暂时解除对工作簿的保护,删除选定的工作表,然后重新保护工作簿。

当然,用户必须习惯这种删除工作表的方式(而不是在工作表的选项卡上右键单击 > 删除)。不过,这并不复杂。

至于如何实现#2,即维护工作表名称列表,我想您可以使用像这样的 UDF(必须称为数组公式):

Function DeletableSheetNames() As String()
    Application.Volatile
    Dim i As Long
    Dim sn() As String
    With ThisWorkbook
        ReDim sn(1 To .Sheets.Count)
        For i = 1 To .Sheets.Count
            With .Sheets(i)
                If .Name = "DataEntry1" Or .Name = "DataEntry2" Then
                    'Don't include it in the list.
                Else
                    sn(i) = .Name
                End If
            End With
        Next i
    End With
    DeletableSheetNames = sn
End Function

【讨论】:

    【解决方案2】:

    您无法阻止用户删除特定工作表,但您可以使用Workbook_BeforeSave() 事件来防止在缺少特定工作表时保存工作簿。此事件的文档准确地显示了如何仅在满足某些条件时才允许保存工作簿。见http://msdn.microsoft.com/en-us/library/office/ff840057(v=office.14).aspx

    【讨论】:

    • 这是个好问题。一旦您开始 VBA 开发,迟早您将面临在让用户玩弄其他工作表的同时保留几张工作表的问题,甚至添加一些新工作表。不幸的是,答案是否定的,对此没有干净的解决方案。从这个角度来看,这里的两种解决方法都有周度。
    【解决方案3】:

    我可以通过 Worksheet_BeforeDelete 事件防止工作表被删除,如下所示:

    Private Sub Worksheet_BeforeDelete()
    
        Call ThisWorkbook.Protect("password")
    
        Call MsgBox("This sheet cannot be deleted.", vbExclamation)
    
    End Sub
    

    这可以保护所有工作表不被删除,但是如果您在 ThisWorkbook 模块上添加一些事件代码,如下所示:

    Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    
        Call ThisWorkbook.Unprotect("password")
    
    End Sub
    

    我将能够在选择任何其他工作表后立即删除它。

    请记住,由于页面在被选中时解锁,您将失去页面之间的复制和粘贴功能。

    【讨论】:

      【解决方案4】:

      “没有可用于检测工作表何时将被删除的事件”

      从 Office 2013 开始,可以使用 SheetBeforeDelete 事件。

      【讨论】:

        【解决方案5】:

        我在 ExtendOffice.com 上找到了这个解决方案,类似于 Dan 的解决方案。将此代码放在 Worksheet 的模块中:

        Private Sub Worksheet_Activate()
        ThisWorkbook.Protect "yourpassword"
        End Sub
        
        Private Sub Worksheet_Deactivate()
        ThisWorkbook.Unprotect "yourpassword"
        End Sub
        

        当您激活相关工作表时,整个工作簿都受到保护,“删除”选项呈灰色显示。当您切换到任何其他工作表时,工作簿将再次空闲。这很微妙,因为您只有在转到“安全”表时才会注意到变化。

        【讨论】:

        • 这是最简单最直接的解决方案。谢谢!!
        【解决方案6】:

        答案是将以下代码添加到每个受保护的工作表中:

        Private Sub Worksheet_Deactivate()
            ThisWorkbook.Protect , True
            Application.OnTime Now, "UnprotectBook"
        End Sub
        

        以下是一个模块:

        Sub UnprotectBook()
            ThisWorkbook.Unprotect
        End Sub
        

        相应地检查 https://www.top-password.com/blog/prevent-excel-sheet-from-being-deleted/ 的信用。

        【讨论】:

          【解决方案7】:

          也许您可以尝试在 SheetBeforeDelete 中保护工作簿的结构。 看我的例子:

          Private Sub Workbook_SheetActivate(ByVal Sh As Object)
              ThisWorkbook.Protect Structure:=False
          End Sub
          
          Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object)
              If Sh.Name = "Example" Then
                  ThisWorkbook.Protect Structure:=True
              End If
          End Sub
          

          【讨论】:

            【解决方案8】:

            这是我基于@Jean-François Corbett 的想法的另一个答案 您可以使用“Protect WB Structure”和事件“Workbook_SheetBeforeDelete”来实现此目的。 结果是会弹出一个对话框说“工作簿受保护,无法更改。”

            Private Sub zPreventWShDel(WSh As Worksheet, Protection As Boolean)
            Dim zPassword As String: zPassword = ""
            Dim zWB As Workbook
            Set zWB = WSh.Parent
            If Protection Then
                zWB.Protect zPassword, Protection
            Else
                zWB.Protect zPassword, Protection
            End If
            
            'Stop
            End Sub
            
            Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object)
            Call zPreventWShDel(Sh, True)
            End Sub
            
            Private Sub Workbook_SheetActivate(ByVal Sh As Object)
            Call zPreventWShDel(Sh, False)
            End Sub
            

            不要像下面那样在工作表停用上调用代码。因为它会停用它。运行顺序为 Event_SheetBeforeDelete -> Event_SheetDeactivate。

            Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
            Call zPreventWShDel(Sh, False)
            End Sub
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-22
              • 1970-01-01
              • 2019-01-14
              • 1970-01-01
              • 2019-03-17
              • 1970-01-01
              • 2012-11-13
              • 1970-01-01
              相关资源
              最近更新 更多