在VB语言中,DOEVENTS的具体的用法和含义

DoEvents的应用及注意事项

转让控制权,以便让操作系统处理其它的事件。

DoEvents 函数会返回一个 Integer,以代表 Visual Basic 独立版本中打开的窗体数目,例如,Visual Basic,专业版,在其它的应用程序中,DoEvents 返回 0。

DoEvents 会将控制权传给操作系统。当操作系统处理完队列中的事件,并且在 SendKeys 队列中的所有键也都已送出之后,返回控制权。

DoEvents 对于简化诸如允许用户取消一个已启动的过程 — 例如搜寻一个文件 — 特别有用。对于长时间过程,放弃控制权最好使用定时器或通过委派任务给 ActiveX EXE 部件来完成。以后,任务还是完全独立于应用程序,多任务及时间片由操作系统来处理。

小心 确保以 DoEvents 放弃控制权的过程,在第一次 DoEvents 返回之前,不能再次被其他部分的代码调用;否则会产生不可预料的结果。此外,如果其它的应用程序可能会和本过程以不可预知的方式进行交互操作,那么也不要使用 DoEvents,因为此时不能放弃控制权。

使用 DoEvents

尽管 Timer 事件是后台处理的最好工具,对耗时极多的任务,情况更是如此,但是,DoEvents 函数还是提供了一种取消任务的简便方法。例如,下列代码将显示一个 "Process" 按钮,单击这个按钮时,它将变成 "Cancel" 按钮。再次单击按钮又将中断正在执行的任务。

'此按钮标题是 "Process"

Private Sub Command1_Click()

'过程的所有实例都共享静态变量。

Static blnProcessing As Boolean

Dim lngCt As Long

Dim intYieldCt As Integer

Dim dblDummy As Double

'按下按钮时,检测是否在处理

If blnProcessing Then

'如果正在处理,则取消

blnProcessing = False

Else

Command1.Caption = "Cancel"

blnProcessing = True

lngCt = 0

'执行一百万次浮点乘法计算。每一千次后,检测是否要取消。

Do While blnProcessing And (lngCt < 1000000)

For intYieldCt = 1 To 1000

lngCt = lngCt + 1

dblDummy = lngCt * 3.14159

Next intYieldCt

'DoEvents 语句允许其它事件发生,包括第二次按此按钮。

DoEvents

Loop

blnProcessing = False

Command1.Caption = "Process"

MsgBox lngCt & " multiplications were performed"

End If

End Sub

DoEvents 将控制切换到操作环境内核。只要此环境中的所有应用程序都有机会响应待处理事件,应用程序就又恢复控制。这不会使应用程序放弃焦点,但会使后台事件能够得到处理。

这种妥协的结果可能并不总是达到预期目标。例如,下述 Click 事件代码在单击按钮后要一直等候十秒钟,而后才显示一条信息。如果在按钮正在等待期间单击它,则将以相反顺序完成单击操作。

Private Sub Command2_Click()

Static intClick As Integer

Dim intClickNumber As Integer

Dim dblEndTime As Double

'每次单击按钮时

'赋予唯一数值。

intClick = intClick + 1

intClickNumber = intClick

'等待十秒。

dblEndTime = Timer + 10#

Do While dblEndTime > Timer

'不做任何事情,仅仅允许

'其它应用程序处理

'它们的事件。

DoEvents

Loop

MsgBox "Click " & intClickNumber & " is finished"

End Sub

对于通过 DoEvents 放弃控制的事件过程,有时可能希望防止在 DoEvents 返回之前重新调用这一过程。否则将无穷无尽地调用该过程,直到系统资源消耗殆尽。可暂时禁止控件,或象上例一样,使用一个静态的“标志”变量防止此事发生。

在使用全局数据时避免 DoEvents

当一个函数已通过 DoEvents 放弃控制时,可相当安全地再次调用函数。例如,下一过程将检测质数并用 DoEvents 语句周期地启动其它应用程序处理事件:

Function PrimeStatus (TestVal As Long) As Integer

Dim Lim As Integer

PrimeStatus = True

Lim = Sqr(TestVal)

For I = 2 To Lim

If TestVal Mod I = 0 Then

PrimeStatus = False

Exit For

End If

If I Mod 200 = 0 Then DoEvents

Next I

End Function

该代码中每重复 200 次就调用一次 DoEvents 语句。这样一来,当该环境的其余部分对事件作出响应时,只要有必要,PrimeStatus 过程就可继续计算。

考虑在调用 DoEvents 期间发生的事情。在其它窗体和应用程序处理事件时将暂停执行应用程序代码。这些事件之一有可能是一个按钮单击操作,它将再次启动 PrimeStatus 过程。

这将导致重新进入 PrimeStatus 过程的,但是,因为在函数每次出现时,堆栈都为其参数和局部变量分配了空间,所以重入不会引发冲突。当然,如果过多调用 PrimeStatus,则可能出现“溢出堆栈空间”错误。

如果 PrimeStatus 使用或改变模块级变量或全局数据,情况就会完全不同。此时,在 DoEvents 能够返回之前执行 PrimeStatus 的另一个实例,这将导致模块数据或全局数据的值完全不同于它们在调用 DoEvents 之前的值。于是,PrimeStatus 的结果将会难以预料。

VB中DoEvents的注意事项

对与再大循环里 加入 DoEvents却是可以使应用程序响应其他程序,但是 DoEvents也会很大程度上影响循环的速度,所以一般情况我这样用

If GetInputState Then DoEvents

虽然多了个判断语句,但速度上确快了很多

比较以下代码代码就知道了速度的差别

Private Declare Function GetInputState Lib "user32" () As Long

Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Command1_Click()

Dim s As Long

s = GetTickCount

For i = 1 To 1000000

DoEvents

Next

MsgBox GetTickCount - s

End Sub

Private Sub Command2_Click()

Dim s As Long

s = GetTickCount

For i = 1 To 1000000

If GetInputState Then DoEvents

Next

MsgBox GetTickCount - s

End Sub