DoEvents应用

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 shawls 的 blog

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

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 的结果将会难以预料。


       以上代码来自: 源代码数据库(sourcedatabase)
           当前版本: 1.0.392
               作者: shawls
           个人主页: http://shawls.yeah.net
             e-mail: shawfile@163.net
                 qq: 9181729

本文关键:语句,DoEvents
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top