我正在使用以下代码来锁定某些单元格的内容
Sub LockCell(ws As Worksheet, strCellRng As String)
With ws
.Unprotect
.Cells.Locked = False
.Range(strCellRng).Locked = True
.Protect Contents:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, AllowInsertingColumns:=True, AllowInsertingRows:=True, AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True, DrawingObjects:=True
End With
End Sub
它锁定这些特定列的内容。问题是用户无法排序,既不过滤也不对单元格应用边框,因为这些Excel菜单项被禁用。
我认为AllowSorting:=True
,AllowFiltering:=True
和DrawingObjects:=True
允许AllowFormattingColumns:=True
和AllowFormattingRows:=True
允许调整大小的方式。
答案 0 :(得分:9)
有很多人都有这种困难。流行的答案是,在不允许无阻碍排序的情况下,您无法保护内容不被编辑。您的选择是:
1)允许编辑和排序:(
2)应用保护并使用代码创建按钮以使用VBA进行排序。还有其他帖子解释了如何执行此操作。我认为有两种方法,或者(1)获取代码以取消保护工作表,应用排序,然后重新保护工作表,或(2)使用UserInterfaceOnly:=True
保护工作表。
3)Lorie的回答不允许用户选择单元格(https://stackoverflow.com/a/15390698/269953)
4)我未讨论的一个解决方案是使用VBA提供一些基本保护。例如,使用Worksheet_Change
检测并还原更改。然而,它远非理想的解决方案。
5)当用户选择数据时,您可以保护工作表,而当用户选择了标题时,可以不受保护。这留下了无数种方式,用户可能会弄乱数据,同时也会导致一些可用性问题,但至少可以降低讨厌的同事不假思索地做出不必要的改变的几率。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If (Target.row = HEADER_ROW) Then
wsMainTable.Unprotect Password:=PROTECTION_PASSWORD
Else
wsMainTable.Protect Password:=PROTECTION_PASSWORD, UserInterfaceOnly:=True
End If
End Sub
答案 1 :(得分:6)
这对我来说是一个主要问题,我发现以下链接的答案相对简单。谢谢Voyager !!!
请注意,我命名了我希望其他人能够排序的范围
http://answers.yahoo.com/question/index?qid=20090419000032AAs5VRR
答案 2 :(得分:3)
我想出了一个获得几乎相同功能的棘手方法。不是以正常方式保护工作表,而是使用事件处理程序撤消用户尝试执行的任何操作。
将以下内容添加到工作表的模块中:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
如果用户做了任何更改已锁定的单元格的操作,则该操作将立即撤消。暂时禁用事件是为了使撤消本身不会触发此事件,从而导致无限循环。
排序和过滤不会触发Change事件,因此这些功能仍然有效。
请注意,此解决方案可防止更改或清除单元格内容,但不会阻止更改格式。只需设置要解锁的单元格,确定的用户就可以绕过它。
答案 3 :(得分:1)
这篇文章解释了问题和解决方案的更多细节:
Sorting Locked Cells in Protected Worksheets
要理解的是,锁定单元格的目的是防止它们被更改,并且排序会永久地更改单元格值。您可以编写宏,但更好的解决方案是使用“允许用户编辑范围”功能。这使得单元格可以编辑,因此排序可以正常工作,但由于单元格在技术上仍处于锁定状态,因此可以阻止用户选择它们。
答案 4 :(得分:1)
Lorie的答案很好,但如果用户选择包含已锁定和未锁定单元格的范围,则可以删除已锁定/受保护单元格中的数据。
Isaac的答案很棒,但如果用户突出显示同时具有锁定和未锁定单元格的范围,则无法解决问题。
如果目标范围内的任何单元格被锁定,我会稍微修改Isaac的代码以撤消更改。它还会显示一条消息,说明撤消操作的原因。结合Lorie的回答,我能够实现所需的结果,即能够对受保护的纸张进行排序/过滤,同时仍然允许用户对未受保护的单元格进行更改。
按照Lorie的回答中的说明操作,然后将以下代码放在工作表模块中:
Private Sub Worksheet_Change(ByVal Target As Range)
For Each i In Target
If i.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
MsgBox "Your action was undone because it made changes to a locked cell.", , "Action Undone"
Exit For
End If
Next i
End Sub
答案 5 :(得分:0)
如果自动过滤是子程序操作的一部分,则可以使用
BioSum.Unprotect "letmein"
'<Your function here>
BioSum.Cells(1, 1).Activate
BioSum.Protect "letmein"
暂时取消保护纸张,过滤细胞,然后重新保护。
答案 6 :(得分:0)
我知道这是超级老,但每当我谷歌这个问题时都会出现。您可以取消上述单元格中给出的范围,然后将数据验证添加到未受保护的单元格中,以引用类似于&#34; 423fdgfdsg3254fer&#34;然后,如果用户尝试编辑任何这些单元格,他们将无法进行编辑,但您现在可以进行排序和过滤。
答案 7 :(得分:0)
这是一个非常古老的线程,但仍然非常有用。我最近带着同样的问题来到这里。我建议在适当的时候保护工作表,并在选择过滤器行(例如第1行)时取消保护它。我的解决方案不使用密码保护-我不需要它(它是一种保护措施,不是安全功能)。我找不到可以识别过滤器按钮选择的事件处理程序-因此,我向用户提供了指示,使其首先选择过滤器单元,然后单击过滤器按钮。这就是我的主张(我只在需要更改保护时才更改保护,这可能会或可能不会节省时间-我不知道,但它“感觉”正确):
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Const FilterRow = 1
Dim c As Range
Dim NotFilterRow As Boolean
Dim oldstate As Boolean
Dim ws As Worksheet
Set ws = ActiveSheet
oldstate = ws.ProtectContents
NotFilterRow = False
For Each c In Target.Cells
NotFilterRow = c.Row <> FilterRow
If NotFilterRow Then Exit For
Next c
If NotFilterRow <> oldstate Then
If NotFilterRow Then
ws.Protect
Else
ws.Unprotect
End If
End If
Set ws = Nothing
End Sub
答案 8 :(得分:-1)
在Excel 2007中,解锁要输入数据的单元格。转到评论
> Protect Sheet
> Select Locked Cells (already selected)
> Select unlocked Cells (already selected)
> (and either) select Sort (or) Auto Filter
不需要VB
答案 9 :(得分:-1)
我有一个类似的问题。我希望用户能够在 受保护的工作表。但是用户无法编辑表。我在上面完成了 使用下面的VBA代码:
Range("Table3").Select
Selection.Locked = True
Selection.FormulaHidden = False
ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True _
, allowfiltering:=True
在以下代码中,我使用VBA过滤了代码:
Range("Table3[[#Headers],[Aantal4]]").Select
ActiveSheet.ListObjects("Table3").Range.AutoFilter Field:=8, Criteria1:= _
Array("1", "12", "2", "24", "4", "6"), Operator:=xlFilterValues