简体   繁体   English

当单元格中的值更改时,私有子更新日期自动

[英]Private sub update date automatically when value in a cell changes

Im trying to automatically update current date in cell T when text in cell Q is "won" and a value in cell AM is > 0. I tried the code below and it is working if first the value in cell is > 0 and then you update the text in cell Q BUT if you do it in another way (first update cell Q and secondly the value in cell AM) the date doesn't appear in cell T.我试图自动更新单元格 T 中的当前日期,当单元格 Q 中的文本“赢得”并且单元格 AM 中的值 > 0 时。我尝试了下面的代码,如果首先单元格中的值 > 0 然后你更新单元格 Q 中的文本,但如果您以另一种方式执行此操作(首先更新单元格 Q,然后更新单元格 AM 中的值),则日期不会出现在单元格 T 中。

Any idea, what Im I missing?任何想法,我错过了什么?

Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [Q:Q]) Is Nothing Then
    If UCase(Target) = UCase("won") And Target.Offset(, 22) > 0 Then
        Target.Offset(, 2) = Int(Now())
    End If
    End If
End sub

Your code only checks for changes in Q therefore the update does not take place if you change AM first.您的代码仅检查 Q 中的更改,因此如果您先更改 AM,则不会发生更新。

My solution has three parts:我的解决方案分为三个部分:

  1. use constants for the columns - in case there are changes to the sheet layout you only have to make adjustments here对列使用常量 - 如果工作表布局发生更改,您只需在此处进行调整
  2. worksheet_change: only check if one of the columns is affected then call the according sub - by that the reader of the code immediately understands what is going on here worksheet_change:只检查其中一列是否受到影响,然后调用相应的子 - 代码的读者会立即理解这里发生了什么
  3. the main routine that inserts the date if condition is met or removes the date if not (maybe you want to adjust this)如果条件满足则插入日期或不满足则删除日期的主例程(也许你想调整它)
Option explicit

Private Const colStatus As String = "Q"
Private Const colValue As String = "AM"
Private Const colDateWon As String = "S"


Private Sub Worksheet_Change(ByVal Target As Range)

Dim c As Range
Set c = Target.Cells(1, 1)

If c.Column = Me.Columns(colStatus).Column Or c.Column = Me.Columns(colValue).Column Then
    updateDateWon c.row
End If
End Sub


Private Sub updateDateWon(row As Long)
'--> adjust the name of the sub to your needs

Dim valueToInsert As Variant
With Me
    If .Range(colStatus & row) = "won" And .Range(colValue & row) > 0 Then
         valueToInsert = Int(Now)
    Else
        'reset the date in case conditions are not met
        valueToInsert = vbNullString
    End If
    Application.EnableEvents = False   'disable events so that change-event isn't called twice
    .Range(colDateWon & row) = valueToInsert
    Application.EnableEvents = True
End With

End Sub

A Worksheet Change Applied to Two Non-Adjacent Columns应用于两个不相邻列的工作表更改

  • You need to monitor columns Q and AM for changes.您需要监控列QAM的变化。
  • You need to account for Target being multiple adjacent and non-adjacent cells.您需要考虑Target是多个相邻和不相邻的单元格。
  • You need to disable events when writing to the worksheet containing this code to not retrigger this event (or trigger any other events).您需要在写入包含此代码的工作表时禁用事件,以免重新触发此事件(或触发任何其他事件)。
  • It is good practice to ensure the re-enabling of events (by using error-handling).确保重新启用事件(通过使用错误处理)是一种很好的做法。
  • You can combine the cells to be written to ( dCell ) into a range ( drg ) and write the stamp in one go.您可以将要写入的单元格 ( dCell ) 合并到一个范围 ( drg ) 中,然后将标记写入一个 go。
  • Int(Now()) or Int(Now) is actually Date . Int(Now())Int(Now)实际上是Date
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)

    On Error GoTo ClearError

    Const sColsAddress As String = "Q:Q,AM:AM"
    Const dCol As String = "T"
    Const fRow As Long = 2 ' (e.g. 2 for excluding headers in the first row)
    Const sCriteria As String = "won"
    
    Dim srg As Range
    With Range(sColsAddress)
        Set srg = Intersect(.Cells, Rows(fRow).Resize(Rows.Count - fRow + 1))
    End With
    
    Dim sirg As Range: Set sirg = Intersect(srg, Target)
    If sirg Is Nothing Then Exit Sub
    
    Dim sirg1 As Range: Set sirg1 = Intersect(sirg.EntireRow, srg.Areas(1))
    Dim siCol2 As Long: siCol2 = srg.Areas(2).Column
    'Dim dirg As Range: Set dirg = sirg1.EntireRow.Columns(dCol) ' not used
    
    Dim siCell1 As Range
    Dim siValue2 As Variant
    Dim drg As Range
    
    For Each siCell1 In sirg1.Cells
        If StrComp(CStr(siCell1.Value), sCriteria, vbTextCompare) = 0 Then
            siValue2 = siCell1.EntireRow.Columns(siCol2).Value
            If IsNumeric(siValue2) Then
                If siValue2 > 0 Then
                    If drg Is Nothing Then
                        Set drg = siCell1.EntireRow.Columns(dCol)
                    Else
                        Set drg = Union(drg, siCell1.EntireRow.Columns(dCol))
                    End If
                End If
            End If
        End If
    Next siCell1
    
    If Not drg Is Nothing Then
        ' Prevent retriggering the event when writing to the worksheet.
        Application.EnableEvents = False
        drg.Value = Now ' only after testing, use 'dDate = Date'
    End If
    
SafeExit:
    ' Enable events 'at all cost'.
    If Not Application.EnableEvents Then Application.EnableEvents = True
    
    Exit Sub
ClearError:
    Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
    Resume SafeExit
End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM