Что делает "DoEvents" в vb6?

Что делает "DoEvents" в vb6 ? Почему я получаю сообщение об ошибке "из стека" ? Что это значит ?

4 ответов


DoEvents () позволяет обрабатывать другие сообщения Windows.

причина, по которой вы получаете ошибку из пространства стека, вероятно, заключается в том, что DoEvents() разрешает события, которые снова вызывают ваш код, который снова вызывает DoEvents (), и так далее, пока пространство стека, которое отслеживает обратные адреса для всех этих вызовов, не закончится.

В общем, я не рекомендую использовать DoEvents () из-за таких проблем и того факта, что он нарушает общий событийный привод дизайн окон.


Я бы уточнил ответ Джонатана в том, что он перекачивает этот цикл сообщений VB и позволяет среде выполнения VB обрабатывать сообщения windows, что является противоположностью сна, который позволяет Windows обрабатывать свои события (не обязательно в мире многоядерных процессоров и истинных многозадачных ОС, но когда VB6 был написан, Windows 9x была доминирующей ОС и жесткий цикл, в котором были только события, Так видеть такие вещи, как

While fDoneFile = False
    DoEvents
    Sleep 55
Wend

был общий шаблон во всем мире VB6.


немного другой способ взглянуть на DoEvents заключается в том, что он сбрасывает события в очереди событий. Если sub или функция запускает событие, этот обработчик событий становится sub, который будет запущен сразу после завершения sub/функции. DoEvents говорит, чтобы запустить этот обработчик событий sub сейчас, а не ждать до конца вашего sub.

хотя я согласен по духу с Джонатаном о том, чтобы не использовать DoEvents, я бы умерил его заявление, сказав, что я рекомендую использовать его, только если вы точно знать, почему, и знать все последствия изменения порядка очереди событий таким образом. Чаще всего DoEvents указывается, когда вы хотите каким-либо образом обновить экран из контекста подпрограммы до завершения выполнения подпрограммы.

примером этого является использование элемента управления ProgressBar. Предположим, вы просматриваете несколько тысяч записей и хотите предоставить пользователю обратную связь о том, как далеко вы продвинулись, обновив индикатор выполнения. Вы можете прерывать цикл каждые сто записей и изменять значение элемента управления progressbar. Однако (если вы не сделаете что-то с этим), вы не увидите изменения на экране до тех пор, пока не запустится обработчик событий изменения progressbar, и этот обработчик не будет запущен, пока ваш sub не будет выполнен. Он просто будет помещен в очередь событий. Чтобы заставить событие change запускаться немедленно, приостановив работу sub, необходимо вызвать DoEvents. Это очистит все существующие события от очередь-в этом случае событие изменения progressbar-и обновит элемент управления progressbar на экране.

теперь "из пространства стека" в основном означает, что вы попали в бесконечный цикл вызовов функций. Самый основной способ вызвать это таков:

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

эта ситуация предполагает два члена массива элементов управления TextBox с именем TextBoxArray. Теперь, если пользователь начинает с первого (индекс 0) и переходит ко второму (индекс 1), то событие LostFocus индекса 0 будет срабатывать. Однако VB также внутренне установит фокус на поле индекса 1. Затем код установит фокус обратно в индекс 0, запустив событие LostFocus индекса 1! Вы попали в петлю. Они исправлено в VB5 или 6, ожидая установки фокуса, пока событие LostFocus не будет выполнено.


Как указано в другом месте, 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