Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Я бы уточнил ответ Джонатона в том, что он накачивает этот цикл сообщений VB и позволяет VB Runtime обрабатывать сообщения Windows, что является противоположностью Sleep, что позволяет Windows обрабатывать свои события (не обязательно в мире многоядерных процессоров и истинная многозадачная ОС, но когда была написана VB6, Windows 9x была доминирующей ОС и сложным циклом, в котором только DoEvents в нем увеличили бы использование ЦП до 100%). Поэтому, видя такие вещи, как

While fDoneFile = False
    DoEvents
    Sleep 55
Wend

был распространенным образцом во всем мире VB6.

Ответ 3

Как указано выше, 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

Ответ 4

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

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

Примером этого является использование элемента управления ProgressBar. Предположим, что вы повторяете несколько тысяч записей и хотите предоставить обратную связь пользователю относительно того, насколько далеко вы продвигаетесь, обновляя индикатор выполнения. Вы можете прервать цикл каждые сто записей и изменить значение на панели управления progressbar. Однако, если вы ничего не сделаете, вы не увидите изменения на экране до тех пор, пока не закончится обработчик события изменения производительности, и этот обработчик не будет выполняться до тех пор, пока ваш субпроцессор не будет выполнен. Он просто будет помещен в очередь событий. Способ принудительного запуска события изменения немедленно, приостановка вашего подпрограммы - вызов DoEvents. Это приведет к удалению всех существующих событий из очереди - в этом случае ваше событие изменения шага прогресса - и обновит элемент управления 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), то произойдет событие 0 LostFocus. Тем не менее, VB также внутренне установил фокус на поле индекса 1. Затем код вернет фокус обратно в индекс 0, индекс обжига 1 LostFocus! Вы попадаете в петлю. Они зафиксировали это в VB5 или 6, ожидая установки фокуса до тех пор, пока не будет выполнено событие LostFocus.