“DoEvents”在vb6中做了什么?

时间:2010-12-24 13:45:08

标签: vb6 doevents

“DoEvents”在vb6中做了什么? 为什么我收到错误消息“堆栈空间不足”?这是什么意思?

4 个答案:

答案 0 :(得分:18)

DoEvents()允许处理其他Windows消息。

出现堆栈空间错误的原因可能是因为DoEvents()允许再次调用代码的事件,再次调用DoEvents(),依此类推,直到跟踪返回地址的堆栈空间为止对于所有这些电话,已经用完了。

一般情况下,我不建议使用DoEvents(),因为这些问题以及它违反了Windows的整体事件驱动设计。

答案 1 :(得分:5)

我会澄清Johnathon的答案,因为它抽取VB消息循环并允许VB运行时处理Windows消息,这与Sleep相反,允许Windows处理其事件(在多核CPU和世界中不是必需的)真正的多任务操作系统,但是当VB6编写时,Windows 9x是主流操作系统,只有DoEvents的硬环路会将CPU使用率提高到100%)。所以看看像

这样的东西
While fDoneFile = False
    DoEvents
    Sleep 55
Wend

是整个VB6世界的常见模式。

答案 2 :(得分:5)

查看DoEvents的一种略微不同的方式是刷新事件队列中的事件。如果您的子或函数触发了一个事件,那么该事件处理程序将成为一个子元素,该子元素在您的子/函数完成后立即运行。 DoEvents现在说要运行该事件处理程序子,而不是等到子结束。

虽然我很同意Jonathon关于不使用DoEvents的意见,但我会说他只是建议你使用它,如果你确切知道原因,并且知道以这种方式更改事件队列顺序的所有后果。大多数情况下,当您想要在子例程执行完毕之前以某种方式从子例程的上下文中更新屏幕时,会指示DoEvents。

此示例是您使用ProgressBar控件时。假设您正在迭代数千条记录,并希望通过更新进度条向用户提供有关您的距离的反馈。您可能会每隔一百条记录中断循环并更改进度条控件上的值。但是(除非你对它做了一些事情)直到进度条的更改事件处理程序运行之后才会在屏幕上看到更改,并且在子程序执行完之后该处理程序将不会运行。它将被放入事件队列中。强制change事件立即运行,暂停sub的方法是调用DoEvents。这将刷新队列中的所有现有事件 - 在这种情况下是您的进度条的更改事件 - 并将更新屏幕上的进度条控件。

现在,“超出堆栈空间”基本上意味着你已经陷入无休止的函数调用循环中。造成这种情况的最基本方法是:

Public sub MySub()
    MySub
End Sub

然后从某处调用MySub。你会得到一个堆栈空间错误。如果你看一下调用堆栈,你会看到很长的MySub调用。

在旧版本的VB中会出现一个众所周知的现实示例:

Public Sub TextBoxArray_LostFocus(index as Integer)
    If TextBoxArray(index) = "" Then
        TextBoxArray(index).SetFocus
        MsgBox "Please enter a value"
    End If
End Sub

这种情况假设一个名为TextBoxArray的TextBox控件数组的两个成员。现在,如果用户以第一个(索引0)开始并移动到第二个(索引1),则将触发索引0的LostFocus事件。但是,VB也会在内部将焦点设置为索引1框。然后代码将焦点设置回索引0,触发索引1的LostFocus事件!你陷入了困境。他们通过等待设置焦点直到LostFocus事件执行完毕,在VB5或6中修复了它。

答案 3 :(得分:4)

如前所述,DoEvents允许应用程序中的其他事件触发。下面是一个如何在没有“堆栈空间不足”问题的情况下使用DoEvents的示例。这可以确保您不会通过使用布尔值多次运行代码来指示代码正在运行。

Sub Example()
    'Create static variable to indicate the sub is running.
    Static isRunning As Boolean
    'Exit the sub if isRunning
    If isRunning Then Exit Sub
    'Indicate sub is running
    isRunning = True
    'Sub does stuff
    DoEvents
    'Ends up calling sub again
    Example 'Added just to prove via testing.
    'Indicate sub is no longer runningrunning
    isRunning = False
End Sub