Excel工作表事件(3)- Change事件連鎖反應

Excel工作表Change事件是最常用的事件代碼之一,通俗的講工作表內容發生變化時,此事件將被激活。這個事件代碼貌似很簡單,事件被激活後,使用代碼想幹啥就幹啥,然後呢 … 就沒有然後了。

先了看一個很常見的需求,在第一行任意單元格輸入任意內容後,在該單元格之下記錄當前的日期,這個就是典型的Change事件應用,3行代碼將搞定。

Private Sub Worksheet_Change(ByVal Target As Range)
    Target.Offset(1, 0) = Date
End Sub

在A1單元格隨便輸入一個字母,按回車結束輸入,啓動着B1單元格自動寫入當前的日期,結果如何呢?
在這裏插入圖片描述
理想很豐滿,現實很骨感。A2單元格確實記錄了我們需要的當前日期,可是之下的幾十個單元格在搞什麼鬼,爲什麼也都被填充了同樣的內容。
我們來分析一下事件代碼的執行過程:

  • A1輸入完成後,Change事件(第一次被激活,記作Change_1)被激活,執行第2行代碼時修改A2單元格的值
  • 此時將Change事件將再次被激活(Change_2),此時Change_1的第3行代碼尚未被執行,執行第2行代碼時修改A3單元格的值
  • 此時將Change事件將再次被激活(Change_3)

如此繼續下去,如果沒有任何資源限制,理論上可以將第1列填滿,但是實際上只填充到A79之後就結束了,並未給出任何錯誤(如果哪位高手知道原因,歡迎留言賜教),估計和遞歸調用的堆棧空間有關。

無論如何,在使用事件代碼時,我們肯定不希望這樣發生這樣的連鎖反應,解決方案也很簡單,使用如下EnableEvents可以禁用系統事件的激活,注意不影響控件事件的激活,例如工作表中的按鈕仍然可以正常響應Click事件。

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    Target.Offset(1, 0) = Date
    Application.EnableEvents = True
End Sub

需要注意在結束事件代碼之前一定要恢復系統的事件激活機制,否者工作表內容的變化,將無法再激活事件代碼。例如如下代碼,只有用戶輸入的內容是數字,並且大於10的時候,纔在其下一行單元格記錄日期。

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    If VBA.IsNumeric(Target.Value) And Target.Value > 10 Then
        Target.Offset(1, 0) = Date
        Application.EnableEvents = True
    End If
End Sub

如果輸入內容不滿足條件,那麼第5行代碼將不會執行,在此之後系統事件將被禁用。正確的事件代碼如下:

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    If VBA.IsNumeric(Target.Value) And Target.Value > 10 Then
        Target.Offset(1, 0) = Date
    End If
    Application.EnableEvents = True
End Sub
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章