根据单元格中的值锁定范围内的单元格

时间:2016-11-02 21:41:01

标签: excel vba excel-vba

我的VBA代码存在一些问题,其目的是:

  1. 在列K
  2. 中触发一次值“X”
  3. 将日期粘贴在同一行的列L中
  4. 锁定K列中的单元格,以便用户选择另一个值然后再次选择X,从而无法在单元格中运行相同的序列,因为这会覆盖日期
  5. 我目前的代码是:

    Private Sub Worksheet_Change(ByVal Target As Excel.Range)
    
    Dim blnUnlockedAllCells As Boolean
    
        If Target.Column = 11 And Target.Value <> "X" Then 
            Exit Sub
    
        ElseIf Target.Column = 11 And Target.Value = "X" Then
            ThisRow = Target.Row
            If Target.Value <> "" Then
                Range("L" & ThisRow).Value = Now
                End If
        End If
    
        If Target.Value <> "X" Then Exit Sub
    
        Const RangeToLock As String = "K8:K1000"
    
        If Target.Cells.Count > 1 Then Exit Sub
    
    
        If Not blnUnlockedAllCells Then
            Me.Cells.Locked = False
            On Error Resume Next
            Me.Range(CStr(RangeToLock)).SpecialCells(2).Locked = True
            On Error GoTo 0
            blnUnlockedAllCells = True
            Me.Protect Password:="PWD", userinterfaceonly:=True 
        End If
    
        If Not Application.Intersect(Target, Me.Range(CStr(RangeToLock))) Is Nothing Then
            If Len(Target) Then Target.Locked = True
        End If
    
    End Sub
    

    似乎锁定RangeToLock中所有非空白的单元格而不是等于“X”的单元格。

    任何帮助将不胜感激,我完全接受有关如何处理上述任何内容的其他建议。

    由于

2 个答案:

答案 0 :(得分:0)

根据您的描述,我猜测您过度思考了这一点。

首先,您似乎已将工作表锁定为UserInterfaceOnly,这意味着您甚至根本不必解锁任何内容。只需更改要锁定的单元格的.Locked属性即可,并且不要轻易保护工作表。

其次,正如我在评论中提到的,Target并不总是只有一个单元格(想想复制粘贴)。这意味着您必须单独遍历Target中的所有单元格。这也意味着您在测试Target.Value <> "X"之前无法测试If Target.Cells.Count > 1,因为如果您获得多个单元格,则会出现类型不匹配运行时错误。

第三,除非您需要根据在L列中写入时间戳来处理其他事件,否则应在编写更改之前禁用事件处理,然后重新启用它。目前,您没有任何方法可以阻止重新进入事件处理程序。

那就是说,你可以简化整个程序,既安全又有工作的愉快副作用:

Private Sub Worksheet_Change(ByVal Target As Excel.Range)
    Dim c As Range
    For Each c In Target
        If c.Column = 11 And c.Value = "X" Then
            Application.EnableEvents = False
            If Not c.Locked Then
                c.Locked = True
                Target.Parent.Cells(c.Row, 12).Value = Now
            End If
            Application.EnableEvents = True
        End If
    Next
End Sub

请注意,这假定工作表已受到保护。如果不是,请将单行If Not Me.ProtectionMode Then Me.Protect "PWD", , , , True添加到过程的顶部,或者(更好)添加Worksheet_Activate()事件。

答案 1 :(得分:0)

对于我对共产国际回答的修改请求,

Private Sub Worksheet_Change(ByVal Target As Excel.Range)

If Target.Cells.Count > 1 Then Exit Sub

PW = "PWD"

Dim iRet As Integer
Dim strPrompt As String
Dim strTitle As String

strPrompt = "Are you sure you want to set this field to X?"
strTitle = "Alert"

If Not Me.ProtectionMode Then Me.Protect PW, , , , True
Dim c As Range
For Each c In Target
    If c.Column = 11 And c.Value <> "X" Then
    Exit Sub

    ElseIf c.Column = 11 And c.Value = "X" Then

    iRet = MsgBox(strPrompt, vbYesNo, strTitle)

     If iRet = vbNo Then
        ActiveCell.ClearContents
        ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True, Password:=PW
        Exit Sub

     ElseIf iRet = vbYes Then
        Application.EnableEvents = False
        If Not c.Locked Then
            c.Locked = True
            Target.Parent.Cells(c.Row, 13).Value = Now
            Target.Parent.Cells(c.Row, 13).Locked = True
        End If
        Application.EnableEvents = True
    End If
    End If
    Next
End Sub

我非常感谢任何关于我如何简化或改善这一点的提示!