Excel VBA工作表更改效率

时间:2016-10-20 17:59:02

标签: vba excel-vba excel

我有一个包含多个工作表更改事件的工作表。不幸的是,由于它们我得到了一些内存错误。我想知道是否有人可以查看这段代码片段并让我知道它是否可以更有效地编写?

当且仅当单元格K4 ="基于事件的"此工作表更改事件调用另一个宏。并且以下每个单元格中都包含一些内容:J12:J15,M12:M14。如果单元格J12:J15,M12:M14已填入并且K4更改为"基于事件"

,我可以调用宏
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("J12") <> "" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim ZRange As Range
Set ZRange = Range("K4")
If ZRange = "Event Based" Then
If Union(Target, ZRange).Address = ZRange.Address Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True

End If
End If
End If

我的问题是,我为每个单独的单元格编写了不同的工作表更改事件。如果K4 =&#34;基于事件&#34;和J13:J15中有一些东西,然后数据被添加到J12

If Range("K4") = "Event Based" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim FRange As Range
Set FRange = Range("J12")
If FRange <> "" Then
If Union(Target, FRange).Address = FRange.Address Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True

End If
End If
End If

我不知道如何编写一个事件,以便如果所有单元格都被填充,则调用宏,这样如果清除了任何一个单元格,则会调用一个名为EventBasedNo的宏。对不起,我对VBA代码不是很熟悉。我确定有办法做到这一点。

1 个答案:

答案 0 :(得分:1)

Regarding speed improvements:

One thing you could do would be to not execute a lot of tests on cell values unless you know that there is a possibility that you are going to need to do that test.

So your current code says:

If Range("J12") <> "" And _
   Range("J13") <> "" And _
   Range("J14") <> "" And _
   Range("J15") <> "" And _
   Range("M12") <> "" And _
   Range("M13") <> "" And _
   Range("M14") <> "" Then
    Dim ZRange As Range
    Set ZRange = Range("K4")
    If ZRange = "Event Based" Then
        If Union(Target, ZRange).Address = ZRange.Address Then
            Application.EnableEvents = False
            Call EventBasedYes
            Application.EnableEvents = True
        End If
    End If
End If

which means that you are looking up the values of J12, J13, J14, J15, M12, M13, M14 and K4, and then deciding whether the worksheet change happened in a cell you are interested in.

By moving the test regarding Target's location earlier, you can save those lookups:

If Not Application.Intersect(Target, Range("K4")) Is Nothing Then
    If Range("J12") <> "" And _
       Range("J13") <> "" And _
       Range("J14") <> "" And _
       Range("J15") <> "" And _
       Range("M12") <> "" And _
       Range("M13") <> "" And _
       Range("M14") <> "" Then
        Dim ZRange As Range
        Set ZRange = Range("K4")
        If ZRange = "Event Based" Then
            Application.EnableEvents = False
            Call EventBasedYes
            Application.EnableEvents = True
        End If
    End If
End If

If a lot of the cells you are checking are likely to be part of the Target of a single Worksheet_Change event then you may be better off testing for all the cells you are interested in first, i.e. using something like:

If Not Application.Intersect(Target, Range("K4,J12,X47")) Is Nothing Then

and then storing the values of the cells that you are frequently referring to in variables (or a Variant array if they are in a contiguous block?) so that you can refer to the variables multiple times rather than have to access the cell itself multiple times.


P.S. Union(Target, ZRange).Address = ZRange.Address is equivalent to Target.Address = ZRange.Address. Is it intentional that your code only fires if a single cell is changed (i.e. you don't want the code to run if cells K2:K6 are changed in a single event, only if K4 is changed by itself)? My proposed change uses an Intersect, which will run if the changed range includes the cell you are interested in, so you should change that back if you don't want that to happen.


Possible rewrite

I think I understand what you are trying to do. Perhaps the following code will do all your tests at once:

If Not Application.Intersect(Target, Range("K4,J12:J15,M12:M14")) Is Nothing Then
    Application.EnableEvents = False
    If Range("J12").Value <> "" And _
       Range("J13").Value <> "" And _
       Range("J14").Value <> "" And _
       Range("J15").Value <> "" And _
       Range("M12").Value <> "" And _
       Range("M13").Value <> "" And _
       Range("M14").Value <> "" And _
       Range("K4").Value = "Event Based" Then
        Call EventBasedYes
    Else
        Call EventBasedNo
    End If
    Application.EnableEvents = True
End If