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

密码保护工作表Excel VBA

  •  1
  • Chopin  · 技术社区  · 6 年前

    我试图为Excel工作簿中的多个工作表提供一种次要的访问保护形式。我知道这不容易实现,而且保护仍然存在问题。

    我有下面的工作代码来说明如何实现这一点。但是,它只能在工作簿中的一个工作表上工作。是否有方法向此代码添加多个工作表。

    注意:我不想创建同一工作簿的多个版本。我只需要一个简单的密码来访问该工作表。我知道这并不能提供一个简单的方法或限制访问

    Private Sub Workbook_Open()
    
    End Sub
    
        Private Sub Workbook_SheetActivate(ByVal Sh As Object)
        Dim MySheetName As String
    
        MySheetName = "Sheet1" 'The first sheet which I want to hide.
        MySheetName = "Sheet2" 'The second sheet which I want to hide.
    
        If Application.ActiveSheet.Name = MySheetName Then
            Application.EnableEvents = False
            Application.ActiveSheet.Visible = False
            response = Application.InputBox("Password", "Enter Password", "", Type:=2)
    
                If response = "1234" Then 'Unhide Password.
                    Application.Sheets(MySheetName).Visible = True
                    Application.Sheets(MySheetName).Select
                End If
        End If
    
        Application.Sheets(MySheetName).Visible = True
    
        Application.EnableEvents = True
        End Sub
    

    此代码只能在单个工作表上使用。它能适应在多张纸上提供保护吗?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Ryan Wildry    6 年前

    我想这就是你要照顾的。您需要一个集合,或者更一般地说,一个可以保存多个值的数据结构。从这里,您可以将值列表与当前激活的工作表进行比较。

    Option Explicit
    Private PreviousSheet As Worksheet
    
    Private Sub Workbook_SheetActivate(ByVal Sh As Object)
        Dim SheetNames As Collection: Set SheetNames = New Collection
        Dim SheetName  As Variant
        Dim response   As String
        Dim ws         As Excel.Worksheet
    
        'List of sheet names you want to hide
        SheetNames.Add "Sheet1"
        SheetNames.Add "Sheet2"
    
        For Each SheetName In SheetNames
            On Error Resume Next
            Set ws = ThisWorkbook.Worksheets(SheetName)
            On Error GoTo 0
    
            If Not ws Is Nothing Then
                If ws.Name = Sh.Name Then
                    Application.EnableEvents = False
    
                    response = Application.InputBox("Password", "Enter Password", "", Type:=2)
    
                    If response = "1234" Then
                        ws.Visible = xlSheetVisible
                        ws.Activate
                    ElseIf response = "False" Or response = vbNullString Then
                        If Not PreviousSheet Is Nothing Then PreviousSheet.Activate
                    Else
                        ws.Visible = xlSheetHidden
                    End If
    
                End If
    
                Application.EnableEvents = True
            End If
        Next
    
    End Sub
    
    Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
        Set PreviousSheet = Sh
    End Sub
    
        2
  •  0
  •   Roy Brander    6 年前

    这是非常快速和肮脏的方式。

    mysheetname=“sheet1 sheet2 sheet_name_fred”

    ….只需列出所有工作表名称,其中有一个空格(或其他内容)。

    然后换你的线路 如果application.activesheet.name=mysheetname,则

    如果instr(mysheetname,sh.name)>0,则

    如果愿意,请使用“application.activesheet.name”而不是“sh.name”。sh”是传递给该标准事件函数的参数,也是刚刚激活的工作表,因此如果将“application.activesheet.name”替换为“sh.name”,代码看起来会更干净一些。

    如果第二个字符串出现在第一个字符串的任何位置(特别是字符位置号),则“instr”函数返回>0。因此,如果ActiveSheet名称出现在长的工作表名称字符串中的任何位置,它将接受密码测试。

    这是“快速而肮脏的”,因为如果您的任何工作表名称是另一个工作表名称的子字符串,它将失败。例如,如果您有名为“总计”和“总计”的工作表,那么如果您将“总计”放在长字符串中,那么激活“总计”也将触发instr函数。 [代码删除] 我刚刚编辑了这个,通过检查工作表名称数组来删除“确定”执行此操作的代码。下面的其他建议是集合或其他数据结构。但有一个简单的方法来证明上述最简单的解决方案的失败。不允许在工作表名称中使用*(或其他几个字符)。所以需要名字的密码字符串可以是:

    MySheetName = "*Sheet1*  *Sheet2*  *Sheet_Named_Fred*"

    然后您的instr搜索名称只需要在工作表名称的两边加上星号:

    IF INSTR(MySheetName, "*"+Sh.Name+"*")>0 Then

    …你完了。不需要集合或其他复杂名称搜索。