我正在尝试在类模块中使用.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"
答案 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模块上的静态方法,只支持标准模块。您希望将环境声明为静态的任何方法都通过包含在标准模块中声明为静态。
因此,将您的回调方法放在标准模块中,并声明一个私有成员,该成员包含对您希望处理该事件的类的特定实例的引用。