【vba】Excel 記錄/修改 記錄的更新時間(使用Worksheet_Change、Workbook_SheetChange事件)


功能概述:

  用指定列來記錄對應行數據是否有更新,如果更新(增刪改),則將當前日期記錄到對應單元格中。

一、運行前准備

運行前准備二選一,由於Excel2007版本以上,基於安全考慮微軟將Excel數據文件與腳本文件分離,數據文件xlsx,腳本文件xlsm。但是2003以下版本數據文件和腳本文件是可以同時保存的。

所以如果是2007以上版本,要么另存后xlsm后添加運行腳本;要么另存為xls后添加運行腳本。

以下是兩種方案

1、基於2007以上版本 -xlsx

  1)修改“保存時從文件屬性中刪除個人信息(R)”,取消√

設置調整后保存vba腳本才不會報錯

 

  2)Excel文件另存為.xlsm文件,因為從2003版本以后為了安全,Excel文件跟腳本文件分開。

在.xlsx下保存vba腳本時報錯信息

  

2、基於2003以下版本-xls

將文件另存為2003以下版本.xls 

 

二、添加腳本代碼

1、鼠標右鍵單擊工作表——“查看代碼”   或通過快捷鍵“Alt+F11”

2、將代碼粘貼進去,並保存關閉即可。

 

三、代碼內容1-基於工作表Worksheet

'功能概述:用指定列來記錄對應行數據是否有更新,如果更新(增刪改),則將當前日期記錄到對應單元格中。
'實現邏輯
'1.通過Worksheet_SelectionChange事件獲取修改前的值
'2.通過變量tagCol設置要記錄修改記錄的列
'3.循環判斷修改后的單元格所在的行(除用來記錄修改記錄的單元格tagCol外)是非空nulFlag=True並直接退出循環
'4.判斷修改的列為非tagCol列,且該行有記錄非空nulFlag=True,且修改前和修改后的值不相等,則將tagCol的值修改為當前日期date()
'5.如果tagCol為空nulFlag=False,則清空tagCol

Option Explicit
Dim oldValue
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'用此事件獲取修改前的值
    oldValue = Target.Value
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
'On Error Resume Next  '跳過異常
On Error GoTo MyErr
'用此事件獲取修改后的值
    Dim row '事件所在的行
    Dim tagCol, col '記錄時間的列
    Dim nulFlag '對應行數據單元格是否非空
    Dim i
    row = Target.row
    col = Target.Column
    tagCol = 8 ' 第8列 "H",即
    nulFlag = False '用來判斷光標所在的行是否為非空,非空為True,空為False
    
    '啟用事件
    'Application.EnableEvents = True
    
    '判斷從該行從1-8內容是否非空
    For i = 1 To tagCol - 1 '最后一列除外
        If Application.WorksheetFunction.CountA(Cells(row, i)) <> 0 Then
            nulFlag = True
            Exit For '如果判斷目標行有非空單元格,則退出循環
        End If
    Next
    
    
    '非tagCol值發生變化,更新tagCol列
    If col <> tagCol And nulFlag = True And oldValue <> Target.Value Then
        Cells(row, tagCol) = Date
    End If
    If nulFlag = False Then
        Cells(row, tagCol) = ""
    End If
    
    '禁用事件
    'Application.EnableEvents = False
MyErr:
    'MsgBox " 錯誤 " & Err.Number & " : " & Err.Description
    Resume Next
End Sub

四、代碼邏輯2-基於工作簿Workbook

基於“三、代碼內容1-基於工作表Worksheet” 的代碼邏輯存在性能和邏輯上的瓶頸,說明如下:

1、以上基於工作表Worksheet的事件,每個工作表都要copy一份代碼,而基於工作簿Workbook的事件只需要一份代碼即可。

2、以上判斷整列是否為空,為空則不處理需要循環逐條判斷,判斷次數較多,效率低;本次直接對整行使用CountA函數,僅進行一次判斷,統計為0則退出事件

3、怎么使用?打開VBE(方式之一:鼠標右鍵單擊工作表名稱,例如Shee1——查看代碼——將代碼復制到ThisWorkbook中),如圖:

4、代碼邏輯如下:

Dim oldvalue '全局變量,用來記錄單元格修改前的值

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    '記錄單元格修改前的值
    oldvalue = Target.Value
End Sub

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    On Error Resume Next  '跳過異常
    
    Application.ScreenUpdating = False '關閉屏幕更新
'排除特定工作表,如果工作表名稱時如下名稱,則退出事件 If Sh.Name = "轉置" Or Sh.Name = "工資條" Or Sh.Name = "商品名稱" Then Exit Sub End If Dim tagCol tagCol = 8 '“修改日期”字段所在工作表的列數,此表為第8列,用邏輯來識別該參數邏輯較為復雜(效率比較低),直接寫死即可 '判斷第1列到“修改日期”列中是否有值,沒有值則退出事件 If Application.WorksheetFunction.CountA(Range(Cells(Target.row, 1), Cells(Target.row, tagCol))) = 0 Then Exit Sub End If '如果同時選擇操作多個單元格,僅處理選中區域內的第一個單元格 If Target.Column > 1 Then Set Target = Target.Cells(1) End If '判斷新舊值不相等,且修改的單元格的列要在“修改日期”的列之前(不包含) If Target.Value <> oldvalue And Target.Column < tagCol Then Cells(Target.row, tagCol) = Date End If
Application.ScreenUpdating = True '恢復屏幕更新 End Sub

五、測試

修改其中一個值,觀察“修改日期”單元格內容是否變化

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM