在自定义类中调用OnTime方法

时间:2014-07-13 12:52:37

标签: vba excel-vba excel

我正在尝试在类模块中使用.OnTime方法,但无法弄清楚如何在类中调用过程。我见过的所有.OnTime示例都是指使用标准代码模块中的方法而不是自定义类。有没有办法在类模块中调用过程而不是标准代码模块?

@Alex P:已更新为包含代码。这是课程模块:

Option Explicit

Public Sub Test()

    MsgBox "Success"

End Sub

Private Sub Class_Initialize()

    Application.OnTime EarliestTime:=Now + TimeValue("00:00:03"), _
                                    Procedure:="Test"

End Sub

标准模块:

Option Explicit

Public Sub TestOnTime()

    Dim OnTime As CCOnTime

    Set OnTime = New CCOnTime

End Sub

我也试过Procedure:="CClass.Test"

2 个答案:

答案 0 :(得分:2)

您可以这样做,但回调需要从标准模块或工作表模块或本工作簿退回到对象中。

这是一个在工作表单元格中脉冲值的示例。 计时器(几乎)封装在cOnTime类中。

cOnTime对象在主机工作表中实例化,其代码模块可以具有设置脉冲时间和回调例程的属性。

如果您保护纸张,它将开始发出脉冲,您可以通过取消保护纸张来阻止它。 如果您离开主机表,计时器将被终止,如果您向后导航,它将重新启动(只要表单受到保护)。

班级cOnTime

Option Explicit
Const DEFPulseTime = "PulseTime"
Const DEFearliestTime As Long = 5
Const DEFlatestTime As Long = 15

Public WithEvents wb As Workbook
Public ws As Worksheet

Private DoWhen As String
Public mPulseTime As Long
Public mNextTime As Double
Property Let callBackDoWhen(cb As String)
    DoWhen = "'" & wb.Name & "'!" & ws.CodeName & "." & cb      'e.g. 'wb Name.xlsm'!Sheet1.kickdog
End Property
Private Function PulseTime() As Long
    On Error Resume Next
         PulseTime = CallByName(ws, DEFPulseTime, VbGet)
         If Err.number <> 0 Then
             PulseTime = DEFearliestTime
         End If
    On Error GoTo 0
End Function
Property Get designMode() As Boolean
    designMode = Not ws.ProtectContents
End Property
Public Sub kickDog()
Const myName As String = "kickDog"
Dim psMessage As String
    If ws Is ActiveSheet And Not designMode Then

        mNextTime = Now + TimeSerial(0, 0, mPulseTime)

        On Error Resume Next
        Application.OnTime mNextTime, DoWhen
        On Error GoTo 0

    End If
    Exit Sub
End Sub
Public Sub killDog()

    If ws Is Nothing Or mNextTime = 0 Then Exit Sub

    On Error Resume Next
    Application.OnTime mNextTime, DoWhen, , False
    On Error GoTo 0

End Sub
Private Sub Class_Initialize()
Dim errorContext As String

    On Error GoTo enableAndExit
        Set wb = ActiveWorkbook
        Set ws = ActiveSheet
    On Error GoTo 0

    callBackDoWhen = DEFDoWhen
    callBackPulseTime = DEFPulseTime
    mPulseTime = PulseTime
    kickDog

    Exit Sub
enableAndExit:
    If Err <> 0 Then
        If ws Is Nothing Then
            errorContext = "ws"
        ElseIf wb Is Nothing Then
            errorContext = "wb"
        End If
    End If
End Sub

Private Sub Class_Terminate()
Const myName As String = "Class_Terminate"

    On Error Resume Next
    killDog
    Set ws = Nothing
    Set wb = Nothing
    Exit Sub

End Sub

Private Sub wb_WindowActivate(ByVal Wn As Window)
    wb_Open
End Sub

Private Sub wb_WindowDeactivate(ByVal Wn As Window)
    killDog
End Sub
Private Sub wb_BeforeClose(Cancel As Boolean)
    killDog
End Sub
Private Sub wb_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If SaveAsUI Then killDog
End Sub

在工作表模块中

Option Explicit

Const cPulseTime As Long = 1

Dim mOnTime As cOnTime
Property Get PulseTime() As Long
    PulseTime = cPulseTime
End Property
'****************************************
'Timer call-back for cOnTime
Public Sub kickDog()
'   Code to execute on timer event
'******************************************
    On Error Resume Next
    Me.Cells(1, 1) = Not Me.Cells(1, 1)
    On Error GoTo 0
'******************************************
    Debug.Print "woof!!"
    mOnTime.kickDog
End Sub

Private Sub Worksheet_Activate()
    Me.Cells(1,1) = False
    Set mOnTime = New cOnTime
End Sub

Private Sub Worksheet_Deactivate()
    On Error Resume Next
    Set mOnTime = Nothing
End Sub

答案 1 :(得分:1)

你在寻求魔力 - VBA是一个全面的工具,但它并不神奇。

原因是每个Class模块都只是一个模板,可以在应用程序代码中实例化任意次。 Excel无法正确猜测Class模块的哪个特定实例是正确调用该方法的实例。您负责做出此决定并管理对相应Class实例的引用。

啊你说 - 但是我想要调用的方法没有使用私有数据/引用。它是静态方法。那么答案就是VBA不支持Class模块上的静态方法,只支持标准模块。您希望将环境声明为静态的任何方法都通过包含在标准模块中声明为静态。

因此,将您的回调方法放在标准模块中,并声明一个私有成员,该成员包含对您希望处理该事件的类的特定实例的引用。