为什么EXCEL VBA返回在终止更改事件后的一个SelectionChange子中间?



请原谅我冗长的解释。我的英语很差,我正在努力做到最好。链接是一个EXCEL 2007工作簿与一些VBA代码(约。70行)。有一个简单的工作表,用户在上面选择d列中的一个单元格。当被选中时,窗口被放大120%,所选的单元格会出现在窗口的左上角。离开单元格后,焦点应该转到相同的行单元格列5,并且缩放回到100%,单元格(1,1)现在位于工作表的左上角。这都是通过Sheet1 IDE中的一些VBA代码来管理的。

奇怪的行为是这样的:

  • 首先,用户选择列4中的Cell。这是由SelectionChange事件处理的。这里的缩放改为120%,选定的单元格被重新定位到窗口的左上角。
  • 其次,用户输入任意类型的字符串值。这首先由Change事件捕获。在这里,右边的单元格,同一行,被VBA代码选中,这触发了另一个SelectionChange事件。
  • 第三,SelectionChange事件包括一个Exit_Sub测试被取消并返回到它离开的Change子。
  • 四,返回到更改子,缩放被调整回100%,然后奇怪的行为发生。这里的VBA应该终止Change子例程。相反,它返回到SelectionChange,并在If_Then测试退出子节点的地方继续执行。

我无法理解为什么VBA返回到SelectionChange事件子程序。此外,为什么在子例程的中间返回而不是在开始,因为SelectionChange子程序是用Exit_Sub命令退出的。出口不是Gosub吗?

我正在努力找出为什么会出现这种奇怪的异常行为。有两个事件正在发生:Worksheet_SelectionChange和Worksheet_Change。我试图将代码清理到最简单的形式,同时再现奇怪的行为。在Worksheet_Change代码中,单元格坐标被捕获,一系列If_Then正在更改缩放、选择和其他验证。

问题:为什么在更改事件子例程终止后,在其代码中间重新实例化SelectionChange子例程?

进一步的调查揭示了在执行代码时一些奇怪的标志值。我添加了一些Debug。打印行尝试调试此问题,发现以下内容:标志ToCol(长变量)记录目标单元格的列值。当Change事件刚好在End_Sub之前时,标志值等于5。当跳转到SelectionChange子例程时,ToCol标志现在等于值4,就好像Target列返回到先前位置列4一样。注意,当跳转到SelectionChange子程序时,代码并没有改变ToCol值。而且,为什么要在子程序的中间跳转回来呢?

我谷歌试图找到任何类似于我的问题,但没有成功,无论是在Stack_Overflow或谷歌一般。

在我的谷歌驱动器上查看SelectionChangeBug EXCEL工作簿上的整个VBA代码注意:代码是有签名的。任何运行它的尝试都需要更改签名。我想不出如何删除签名。

Option Explicit
Public SystemBuzy As Boolean
Dim FromCell As Range, ToCell As Range
Dim BuzyHere As Boolean, LargeTarget As Boolean, FromIsEmpty As Boolean, ToIsEmpty As Boolean
Dim FromRow As Long, FromCol As Long, ToRow As Long, ToCol As Long
Private Sub Worksheet_Change(ByVal Target As Range) ' Value Change 
Call SetPrevious(Target)
Debug.Print "       Value Changed"
BuzyHere = BuzyHere Or SystemBuzy
LargeTarget = IsRangeLarge(FromCell)
If BuzyHere Or LargeTarget Then
Exit Sub
End If
If ToRow > 2 And ToCol = 4 And Not ToIsEmpty Then
BuzyHere = True
ToCol = 5
Sheet1.Cells(ToRow, ToCol).Select
ActiveWindow.Zoom = 100
ActiveWindow.ScrollRow = 1
ActiveWindow.ScrollColumn = 1
End If
If ToRow > 2 And ToCol = 5 And MathVal(ToCell) > 0.01 Then
BuzyHere = True
'Call DoSomething Not related
End If
BuzyHere = False
End Sub
'_______________________________________________________________________
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Call SetPrevious(Target)
Debug.Print "   Selection Changed"
BuzyHere = BuzyHere Or SystemBuzy
LargeTarget = IsRangeLarge(FromCell)
If BuzyHere Or LargeTarget Then
Exit Sub
End If
If ToRow > 2 And ToCol = 4 Then
ActiveWindow.Zoom = 120
Application.Goto ActiveCell, Scroll:=True
Else
ActiveWindow.Zoom = 100
ActiveWindow.ScrollRow = 1
ActiveWindow.ScrollColumn = 1
End If

BuzyHere = False
End Sub
Private Sub SetPrevious(TheTarget As Range)
Set ToCell = TheTarget.Cells(1, 1)
If FromCell Is Nothing Then Set FromCell = ToCell
FromCol = FromCell.Column: FromRow = FromCell.Row
ToRow = ToCell.Row: ToCol = ToCell.Column
FromIsEmpty = ToIsEmpty
ToIsEmpty = IsEmpty(ToCell)
Set FromCell = ToCell

Debug.Print "FromRow:" & FromRow, "FromCol:" & FromCol, "ToRow:" & ToRow, "ToCol:" & ToCol;

End Sub
' =====  Here these public functions are into a different module  =====
Option Explicit
Option Base 1

Public Function TrimMil(Brut As Double) As Double
TrimMil = Int(Brut * 100 + 0.5) / 100
End Function
Public Function MathVal(TheCell As Variant) As Double
If IsNumeric(TheCell.Value) Then
MathVal = TrimMil(Val(TheCell.Value))
Else
MathVal = 0
End If
End Function
Public Function IsRangeLarge(TheRange As Range) As Boolean
If TheRange Is Nothing Then
IsRangeLarge = False
Exit Function
End If

If TheRange.Rows.Count > 1 Or TheRange.Columns.Count > 1 Then
IsRangeLarge = True
Exit Function
End If

IsRangeLarge = False
End Function

下面是一个简单的例子:

Private Sub Worksheet_Change(ByVal Target As Range)
Target.Offset(1).Select
Debug.Print "still in change event"
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Debug.Print "selectionchange event"
End Sub

编辑单元格的输出是:

still in change event
selectionchange event

所以-触发Worksheet_SelectionChange不会立即运行相关的事件代码-它是"排队"的;直到Worksheet_Change事件码退出。

相关内容

最新更新