【问题标题】:Excel VBA Worksheet Change Event assigned已分配 Excel VBA 工作表更改事件
【发布时间】:2018-02-22 04:39:22
【问题描述】:

使用 Excel 2007,我知道我可以在它创建的工作表上创建 worksheet_change 事件。

但是如何将全局子更改事件分配给新创建的工作表?

例如

Public Sub DataChange(ByVal Target As Range)
  ' this will check and see if the user or operator has change the column field
  ' if they fill in "X", mark the whole row to red color
  ' otherwise leave it black
  Dim KeyCells As Range
  Dim LastRow As Long
  LastRow = Cells(Rows.Count, 1).END(xlUp).Row
  Set KeyCells = Range("L2:L" & LastRow)

  If Not Application.Intersect(KeyCells, Range(Target.Address)) _
    Is Nothing Then
    If Target.Value = "X" Or Target.Value = "x" Then
        Target.EntireRow.Font.color = vbRed
    Else
        Target.EntireRow.Font.color = vbBlack
    End If
  End If
End Sub

然后在Module1中的一个单独的子过程中...

Public Sub CreateWorkSheet() 
  Dim ws As Worksheet

  Set ws = Sheets.Add
  ws.Name = "Test1"
  ' Here where I want to set the event but I do not know the syntax
  ' ws.OnChange = DataChange

  Debug.Print "Done"

End Sub 

我习惯于在创建控件 (C#/WPF/Pascal) 时动态分配事件,所以我认为 Excel 世界中会有一个。任何建议或帮助将不胜感激。

【问题讨论】:

  • 如果您创建一个空白工作表,将代码添加到工作表的代码表并将其隐藏,您可以复制它或将其用作未来新工作表的模板,代码将随之而来。或者,您可以选择 Workbook_SheetChange 事件处理程序。
  • 问题,Excel 如何知道运行宏的工作表?我认为它仅限于它所关注的选定工作表?在这种情况下,更新单元格的代码被隐藏了,但是代码如何继续在另一个工作表上运行?听起来像是在 Excel 中发生的覆盖功能?另外这个问题是我可能只想在某些工作表上使用 sub 而不是全部。
  • A Worksheet_Change 只有 Target 传递给它; Workbook_SheetChange 具有 Sh 用于工作表和目标。我喜欢使用 Select Case 来解析工作表名称。
  • ...是的,您的 DataChange 将需要对所有范围和单元格调用进行适当的父工作表引用,但是,这些应该从一开始就存在。

标签: vba excel


【解决方案1】:

正如 Jeeped 所提到的,可能最简单的方法是复制后面已经有 Private Sub Worksheet_Change 代码的工作表,但还有另一种方法,如果您将以下代码放在 ThisWorkbook 下,每当一个新的工作表被创建,它将在其后面添加所需的代码:

Private Sub Workbook_NewSheet(ByVal Sh As Object)
    Dim NewSheet As Worksheet
    Set NewSheet = Sheets(ActiveSheet.Name)
    Code = "Private Sub Worksheet_Change(ByVal Target As Range)" & vbCrLf
    Code = Code & "MsgBox ""your code here""" & vbCrLf
    Code = Code & "End Sub"
    With ThisWorkbook.VBProject.VBComponents(NewSheet.Name).CodeModule
    NextLine = .CountOfLines + 1
    .InsertLines NextLine, Code
    End With
End Sub

这里的缺点是需要通过单击 Trust access to the VBA project object model 来更改宏的信任设置:

编辑:

您也可以使用类似的方法将代码从一个工作表复制到另一个工作表:

Sub test()
Dim CodeCopy As VBIDE.CodeModule
Dim CodePaste As VBIDE.CodeModule
Dim numLines As Long

Set CodeCopy = ActiveWorkbook.VBProject.VBComponents("Sheet1").CodeModule
Set CodePaste = ActiveWorkbook.VBProject.VBComponents("Sheet2").CodeModule

numLines = CodeCopy.CountOfLines
'Use this line to erase all code that might already be in sheet2
'If CodePaste.CountOfLines > 1 Then CodePaste.DeleteLines 1, CodePaste.CountOfLines

CodePaste.AddFromString CodeCopy.Lines(1, numLines)
End Sub

【讨论】:

  • 有趣。这看起来像是在运行中显式创建潜艇,而不是分配预先存在的潜艇。这种方式要复杂得多,但这是一个很好的替代解决方案。谢谢!
  • @Skibur 我已经编辑了我的答案以包含一种将代码从一个工作表复制到另一个工作表的方法,希望这会有所帮助。 :)
  • 更好!非常感谢您的回答。我确实提到我只想将此规则应用于新创建的工作表。到目前为止,这是最好的解决方案。
  • @Skibur,另一个注意事项,当引用工作表名称时,它应该是工作表的代码名称,而不是选项卡名称,您可以使用 Worksheets("Sheet1").CodeName 之类的名称获得,希望这是有道理的。
  • @Xabier Huh,伙计,我欠你一个!使用 Name 而不是 CodeName 会导致未定义的行为,我浪费了几个小时进行故障排除。
【解决方案2】:

我会接受@Jeeped 的最后一个建议

将此代码放在ThisWorkbook 代码窗格中

Option Explicit

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    DataChange Target ' this sub will be called at any change of any worksheet passing the chenged range
End Sub

然后将其放在同一代码窗格或任何其他模块中

Public Sub DataChange(ByVal Target As Range)
  ' this will check and see if the user or operator has change the column field
  ' if they fill in "X", mark the whole row to red color
  ' otherwise leave it black
  Dim KeyCells As Range
  Set KeyCells = Range("L2:L" & Cells(Rows.Count, 1).End(xlUp).Row)

  If Not Application.Intersect(KeyCells, Target) Is Nothing Then Target.EntireRow.Font.color = IIf(UCase(Target.Value2) = "X", vbRed, vbBlack)
End Sub

【讨论】:

  • 很好的答案,但它如何分配给特定的工作表?
  • Workbook_SheetChange 事件将在工作簿中的 any 工作表发生更改时触发,因此它不会分配给特定工作表而是分配给所有工作表。正在更改的工作表保存在 sh 参数中,更改的单元格保存在 Target 参数中。
猜你喜欢
  • 1970-01-01
  • 2016-11-11
  • 2021-02-15
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多