嗯,标题说明了一切。我有一个带有VBS类的HTA,我试图用另一个类sub作为其“函数”参数调用setInterval,但是我得到一个“类型不匹配”错误。 这可以通过任何直接或解决方式的黑客形式完成吗?我唯一能想到的就是在类之外使用“参数”函数,但这首先击败了类的目的...... 救命啊!
编辑(示例代码):
Class My_Class
Private TimerID
Public Sub Sub1(param)
Dim x
x = DoSomeCalculations(param)
TimerID = window.setInterval("Sub2(x)", 1000, "VBScript")
End Sub
Private Sub Sub2(param)
Dim y
y = DoSomeMoreCalculations
If param = y Then window.clearInterval(TimerID)
End Sub
End Class
答案 0 :(得分:1)
迟到的答案,但......应该有效:
Class My_Class
Private TimerID
Public Sub Sub1(param)
Dim x
x = DoSomeCalculations(param)
Dim cb
Set cb = New MyCallback
Set cb.Target = Me
cb.ParamValue = x
TimerID = window.setInterval(cb , 1000, "VBScript")
End Sub
' must be Public
Public Sub Sub2(param)
Dim y
y = DoSomeMoreCalculations
If param = y Then window.clearInterval(TimerID)
End Sub
End Class
Class MyCallback
Public Target
Public ParamValue
' must be Public and Default
Public Default Sub DoCall
Target.Sub2 ParamValue
End Sub
End Class
window.setTimeout和window.setInterval将调用Default Sub或Default Function。不幸的是,它不能用在事件处理程序中。
答案 1 :(得分:0)
根据this article我想法,setInterval会将'function'字符串传递给GetRef(),但它似乎更像是eval:
<html>
<head>
<Title>SetIntervalDemo</Title>
<hta:application id="SetIntervalDemo" scroll = "no">
<script type="text/vbscript">
Dim g_sp0
Sub sp0()
MsgBox "sp0 called"
ClearInterval g_sp0
End Sub
Sub sisp0()
g_sp0 = SetInterval(GetRef("sp0"), 1000)
' g_sp0 = SetInterval("mp0", 1000) <---- Type Mismatch
End Sub
Dim g_sp1
Sub sp1(x)
MsgBox "sp1 called: " & x
ClearInterval g_sp1
End Sub
Sub sisp1()
g_sp1 = SetInterval("sp1(4711 + g_sp1)", 1000)
End Sub
Dim g_mp0_a
Dim g_o_a
Dim g_mp0_b
Dim g_o_b
Sub simp0()
Set g_o_a = New cC : g_o_a.m_sName = "Alpha"
Set g_o_b = New cC : g_o_b.m_sName = "Beta"
g_mp0_a = SetInterval("g_o_a.mp0", 1000)
g_mp0_b = SetInterval("g_o_b.mp0", 1000)
End Sub
Class cC
Public m_sName
Public Sub mp0()
MsgBox m_sName & ".mp0 called"
ClearInterval g_mp0_a
ClearInterval g_mp0_b
End Sub
End Class
</script>
</head>
<body>
<input type="button" value="sp0" onclick="sisp0" />
<input type="button" value="sp1" onclick="sisp1" />
<input type="button" value="mp0" onclick="simp0" />
</body>
</html>
因此,使用Subs,一些全局变量和方法调用("g_o_a.mp0"
)可能是定期调用方法的方法。 (在生产代码中使用之前,请仔细测试。)
答案 2 :(得分:0)
我认为不可能在实例本身中调用一个方法(即通过Me
),因为在调用计时器时上下文会丢失。
你可以使用全局变量(尽管很讨厌)。问题在于,如果您有多个同一个类的实例,则每个实例都需要一个全局变量,并且代码需要知道要调用的变量。
但是,上面有一个解决方法 - 使用数组或字典作为单个全局对象,然后使用名称或ID来标识该集合中的实例。
现在,当您使用计时器时,调用类外部的方法,将实例的标识符作为值传递。您调用的方法可以在集合中查找此id,返回您的实例,然后可以在该实例上调用相关方法。
有点破解,但它有效 - 可以在下面使用演示hta应用程序看看它的实际效果。
搜索字符串'!Important
以查看代码的关键位。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/vbs" language="vbscript">
option explicit
dim dummies '!Important - this is the global variable holding all your instances
sub CreateDummyInstances()
dim dum
set dummies = CreateObject("Scripting.Dictionary")
set dum = (new Dummy)("Makaveli84", 5000)
set dum = (new Dummy)("JohnLBevan", 7000)
set dum = (new Dummy)("Ekkehard.Horner", 10000)
set dum = nothing
end sub
class Dummy
private m_name
private m_timeoutMilSec
private m_timerOn
private m_timerRunningLock
private sub Class_Initialize
m_timerOn = false
m_timerRunningLock = false
end sub
public default function Dummy(name, timeoutMilSec)
m_name = name
m_timeoutMilSec = timeoutMilSec
dummies.add name, me '!Important - add this new instance to our collection
CreateButton
set Dummy = me
end function
public property Get Name
Name = m_name
end property
public property Get IsTimerOn
IsTimerOn = m_timerOn
end property
public sub BeginTimer()
m_timerOn = true
if not m_timerRunningLock then 'avoid creating two threads if an off-on occurs within a single timer wait
TimerLoop
end if
end sub
public sub EndTimer()
m_timerOn = false
end sub
public sub TimerLoop()
if m_timerOn then 'get out of jail free (altered by separate thread)
m_timerRunningLock = true
PerformSomeAction
'this doesn't work because Me loses its context when called by the timer
'window.setTimeout "Me.TimerLoop", m_timeoutMilSec, "VBScript"
'so instead we pass a name / id for this object as a parameter to an external function
'and have that lookup this instance and externally call the method we wanted to call
window.setTimeout "TheFunkyTrick(""" & m_name & """)", m_timeoutMilSec, "VBScript" '!Important - call the external function
else
m_timerRunningLock = false
end if
end sub
private sub CreateButton()
dim p
dim button
set p = document.createElement("p")
set button = document.createElement("button")
button.id = "btnStart" & m_name
button.innerText = "Start " & m_name
AddClickEventHandler button, "StartTimer"
p.appendChild button
set button = document.createElement("button")
button.id = "btnStop" & m_name
button.innerText = "Stop " & m_name
AddClickEventHandler button, "StopTimer"
p.appendChild button
divButtons.appendChild p
set button = Nothing
set p = Nothing
end sub
private sub AddClickEventHandler(objButton, strFunctionName)
dim fun
set fun = getRef(strFunctionName)
call objButton.attachEvent("onclick", fun)
set fun = Nothing
end sub
sub PerformSomeAction
msgbox "Hello from " & m_name & ". I show up every " & cstr(cint(m_timeoutMilSec/1000)) & " seconds, until stopped."
end sub
end class
function vbInit()
CreateDummyInstances
end function
function GetDummy(name)
if dummies.exists(name) then
set GetDummy = dummies(name) '!Important - get desired instance from the collection (assuming it exists)
else
msgbox "name not found: " & name
set GetDummy = nothing 'the way I've coded stuff below this would cause an exception (i.e. since I've not bothered to check if it's nothing) - but as this is a demo that's fine
end if
end function
function GetNameFromButtonEvent(objEvent, boilerplate)
GetNameFromButtonEvent = Right(objEvent.srcElement.Id, len(objEvent.srcElement.Id) - len(boilerplate))
end function
sub StartTimer(objEvent)
dim name
name = GetNameFromButtonEvent(objEvent, "btnStart")
GetDummy(name).BeginTimer
end sub
sub StopTimer(objEvent)
dim name
name = GetNameFromButtonEvent(objEvent, "btnStop")
GetDummy(name).EndTimer
end sub
sub TheFunkyTrick(name) '!Important - call the method on the relevant instance
GetDummy(name).TimerLoop
end sub
</script>
<HTA:APPLICATION
ApplicationName="Stack Overflow VBScript Class Timer Demo"
Caption="Yes"
icon="img/favicon.ico"
Scroll="no"
SingleInstance="yes"
WindowState="normal"
ShowInTaskbar="Yes"
SysMenu="Yes"
MaximizeButton="No"
ShowInTaskbar="Yes"
MinimizeButton="No"
Navigable="No"
Border="Thin"
BORDERSTYLE="Complex"
INNERBORDER="No"
/>
<title>Stack Overflow VBScript Class Timer Demo</title>
</head>
<body onload="vbInit()" language="vbscript">
<h1>Demo</h1>
<div id="divButtons"></div>
</body>
</html>