有没有办法跟踪哪个Sub已经运行

时间:2018-01-03 16:47:01

标签: excel vba excel-vba

这是一个理论问题,而不是其他任何东西,如果可能的话,我可以使用它。

我在互联网上看,却一无所获。

excel是否有办法跟踪Sub已运行的内容,然后在if语句中使用此信息?

即。

假设我们有Sub 1,Sub 2,Sub 3,Sub 4& Sub 5

子调用next sub取决于结果。我需要很多子,因为用法将涉及UserForms以及模块。

如果

Sub 1 - > Sub 2 - > Sub 3 - > Sub 5

但是如果Sub 3被调用,Sub 5将不会运行。

所以

Sub 1 - > Sub 2 - > Sub 4 - > Sub 5 - 但现在是5次运行。

这是否有意义/是否可能(我需要更强大的语言吗?)?

3 个答案:

答案 0 :(得分:3)

您基本上想要在模块/项目中创建状态引擎。此状态引擎将处于全局级别,并且每个函数/子例程将在运行时更改状态。

我会考虑每个函数/例程都应该在进入和离开时触发事件。您的状态机将监听每个事件并相应地修改状态。

如果在继续操作之前有依赖于特定状态的函数/例程,则添加其他代码以查询当前状态。解决此问题的另一种方法是在尝试触发函数/子例程之前进行状态查询。取决于您希望代码执行的操作以及在尝试执行无效代码分支时您希望它如何响应。

答案 1 :(得分:1)

是的,你可以做到!请按照以下步骤操作:

  1. 创建一个程序(子程序)
  2. 创建4个函数,这些函数返回true / false值(取决于你想得到什么结果)
  3. 在程序中你可以使用像变量
  4. 这样的函数

    例如:

     Sub TrackSubroutines
         If Function1(parameters) Then
            If Functions2(parameters) Then
        '... and so on
            End If
         End If
     End Sub
    
    Function1(parameters) As Boolean
        Function1 = True/False
    End Function
    
    Function2(parameters) As Boolean
        Function1 = True/False
    End Function
    

    您可以在MSDN找到更多内容:Calling Sub and Function Procedures

答案 2 :(得分:1)

通过日志变量State

进行逼近

使用Type变量将跟踪代码存储在日志变量中,向您展示一种可行的方法。我建议在额外的代码模块中将其声明为公共类型模式“TLog”,例如: “modGlobals”。

使用全局变量的额外模块中的声明头

   Option Explicit
   Public Type TLog                   ' <~~  declare Public Type TLog e.g. in module 'modGlobals'
          nTimes As Integer
          State  As String
   End Type

代码模块中的声明头

您可以在这里定义自己的日志,例如: log1基于TLog类型。 此外,您添加一个常量代码字符串“124”,定义触发sub5的后续subs(sub1 + sub2 + sub4)。

Option Explicit                         ' declaration head in your code module
Dim log1 As TLog                        ' module log book comprising state code and times executed
Const MYCOND As String = "124"          ' code string for condition: sub1 + sub2 +  sub4

方式

任何过程调用都会运行用户定义的跟踪过程,其中包含三个主要任务:

  • (1)将过程代码添加到日志变量(例如log1.State
  • (2)检查子条件“124”(sub1 + sub2 + sub4)
  • (3)如果观察到过程顺序sub1 + sub2 + sub4,则运行sub5。

(警告:如果你想记录超过9个后续的潜艇,你必须调整记录方法,只为每个潜艇加上一位数

注意

我弃权使用(优选的)类方法以向您展示方式。当然你可以在SO找到一些想法。

如何在相关潜艇中使用跟踪程序

只需在任何相关程序中调用Track 1Track 2等等(跟踪潜艇并默认检查严格的订单)。但是,我提出了通过将第二个参数设置为False来选择任何顺序的可能性。

Sub sub1()
    track 1
    ' ...
End Sub
Sub sub2()
    track 2
    ' ...
End Sub
Sub sub3()
    track 3
    ' ...
End Sub
Sub sub4()
    track 4
    ' ...
End Sub
Sub sub5()
    ' Purpose: run code only after sub1 + sub2 + sub4
    ' ...
    Beep
End Sub

示例电话

Sub test()
' Purpose: Testing wanted series of procedures
sub1
sub2
sub4        ' << if modified to sub3, there will be no execution
End Sub

跟踪程序的代码示例

在代码注释中写入解释:

Sub track(ByVal i As Integer, Optional bStrictOrder As Boolean = True)
' Purpose: track procedures sub1 to sub4 and run sub5 if the logged state string has a defined order (without sub3)
' Method:  the state code is logged in a declared TYPE variable, e.g. log1
' Extra:   an additional execution counter nTimes
' Note:    the constant string MYCOND "124" codes the sequence sub1 + sub2 + sub4
Dim bExecProc As Boolean            ' flag to procede in code
Dim yn        As VbMsgBoxResult     ' yes/no answer to messagebox question

  ' (0) log only first 4 procedures as precondition to execute sub5
    If i >= 5 Then Exit Sub             ' just in case of additional track statements in higher subs


  ' -------------------------------------------------------
  ' (1) track procedures by adding digit code to log1.State
  '     (reinitiate log1 after procedure sub1)
  ' -------------------------------------------------------
    log1.State = IIf(i = 1 And bStrictOrder, "", log1.State) & Format(i, "0")
  ' note: might demand further code to avoid subsequent calls of the same procedure 
  ' 
  ' -------------------------------------------
  '  (2) Check defined condition code
  ' -------------------------------------------
  If bStrictOrder Then
  '  (2a) sub1 + sub2 + sub4 have run before in defined ORDER
          If log1.State = MYCOND Then bExecProc = True
  Else
  '  (2b) alternative: sub1, sub2 and sub4 have run in ANY order
          If Arrange(log1.State) = MYCOND Then bExecProc = True
  End If

  ' -------------------------------------------
  '  (3) Execute procedure sub5
  ' -------------------------------------------
    If bExecProc Then
    ' optional security message if sub5 has been already executed before
      If log1.nTimes = 0 Then
       yn = vbYes
      Else
       yn = MsgBox("Sub5 has been executed already " & log1.nTimes & " time(s). " & _
            "Do you want to procede?", vbQuestion + vbYesNo + vbDefaultButton2, "Attention")
      End If
      If yn = vbYes Then
      ' do it and reset state and execution counter
        MsgBox "I'm calling sub5 now" & vbNewLine & " because " & vbNewLine & _
             " log1.State code shows """ & log1.State & """" & vbNewLine & vbNewLine & _
             " (log1.nTimes = " & log1.nTimes & " time(s) up till now)", vbInformation, "Just before running Sub5"
      ' ~~~~~~
        sub5                             ' <~~ execute procedure sub5
      ' ~~~~~~
        log1.State = ""                  ' reset state
        log1.nTimes = log1.nTimes + 1    ' increment execution counter
      End If

    End If


End Sub

在任何程序顺序的情况下帮助函数

辅助函数Arrange()仅在您将所有Track次调用设置为False的第二个(可选)参数时使用,例如Track 1, False

Function Arrange(ByVal s As String) As String
' Purpose: Helper function to rearrange State code for logging (e.g. log1.State)
' caveat:  limited to 9 subsequent subs with single digits
' Note:    (admittedly code could be refined)
  Dim i As Integer       ' counter
  ReDim v(1 To Len(s))
  Dim d As Integer       ' each digit in code s
' loop through State code characters so far
  For i = 1 To Len(s)
      v(i) = Val(Mid(s, i, 1))
  Next i
  SortAr v
' return rearranged code string
  Arrange = Join(v, "")
End Function

Sub SortAr(arr())
' Purpose:  sort one based 1-dim array
' cf: https://stackoverflow.com/questions/20721489/how-can-i-sort-dates-in-an-array-in-vba
Dim Temp
Dim i As Long, j As Long

For j = 1 To UBound(arr)
    Temp = arr(j)
    For i = j - 1 To 1 Step -1
        If (arr(i) <= Temp) Then GoTo 10
            arr(i + 1) = arr(i)
    Next i
    i = 0
10:     arr(i + 1) = Temp
Next j
End Sub