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

Отмена длительного процесса в VB6.0 без DoEvents?

Можно ли отказаться от долгого процесса в VB6.0 без использования DoEvents?

Например:

for i = 1 to someVeryHighNumber
    ' Do some work here '
    ...

    if cancel then
        exit for
    end if
next

Sub btnCancel_Click()
    cancel = true
End Sub

Я предполагаю, что мне нужно "DoEvents" перед "if cancel then...", есть ли лучший способ? Это было некоторое время...

4b9b3361

Ответ 1

Нет, вы правильно поняли, вы определенно хотите DoEvents в своем цикле.

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

' at the top:
Declare Function GetQueueStatus Lib "user32" (ByVal qsFlags As Long) As Long

' then call this instead of DoEvents:
Sub DoEventsIfNecessary()
    If GetQueueStatus(255) <> 0 Then DoEvents
End Sub

Ответ 2

Нет, вам нужно использовать DoEvents, иначе все события пользовательского интерфейса, клавиатуры и таймера будут оставаться в очереди в очереди.

Единственное, что вы можете сделать, это вызвать DoEvents один раз на каждые 1000 итераций или таких.

Ответ 3

Является ли цикл "for" запущенным в потоке графического интерфейса? Если да, то вам понадобится DoEvents. Вы можете использовать отдельный поток, и в этом случае DoEvents не требуется. Вы можете сделать это в VB6 (не просто).

Ответ 4

Вы можете запустить его в отдельном потоке, но в VB6 это королевская боль. DoEvents должны работать. Это взломать, но тогда и VB6 (10-летний ветеран VB говорит здесь, поэтому не меняйте меня).

Ответ 5

Разделите задачу с длительностью работы на кванты. Такие задачи часто управляются простым циклом, поэтому разрезайте его на 10, 100, 1000 и т.д. Итераций. Используйте элемент управления таймером, и каждый раз, когда он срабатывает, выполняет часть задачи и сохраняет свое состояние во время движения. Для начала настройте начальное состояние и включите таймер. По завершении отключите таймер и обработайте результаты.

Вы можете "настроить" это, изменив, сколько работы сделано на квант. В обработчике событий Timer вы можете проверить "отменить" и остановиться по мере необходимости. Вы можете сделать все это аккуратно, объединив рабочую нагрузку и таймер в UserControl с событием Completed.

Ответ 6

Это хорошо работает для меня, когда мне это нужно. Он проверяет, нажал ли пользователь клавишу эвакуации, чтобы выйти из цикла.

Обратите внимание, что у него действительно большой недостаток: он обнаружит, что пользователь нажимает клавишу escape в ЛЮБОМ приложении - а не только на вас. Но это отличный трюк в разработке, когда вы хотите дать себе возможность прервать длинный цикл работы или способ удерживать клавишу shift для обхода части кода.

Option Explicit

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer

Private Sub Command1_Click()
    Do
        Label1.Caption = Now()
        Label1.Refresh
        If WasKeyPressed(vbKeyEscape) Then Exit Do
    Loop

    Label1.Caption = "Exited loop successfully"

End Sub

Function WasKeyPressed(ByVal plVirtualKey As Long) As Boolean
    If (GetAsyncKeyState(plVirtualKey) And &H8000) Then WasKeyPressed = True
End Function

Документация для GetAsyncKeyState находится здесь:

http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx

Ответ 7

ИЗМЕНИТЬ он , статья MSDN ошибочна, а метод DOESN 'T WORK: (

Здесь приведена статья об использовании компонента .NET BackgroundWorker для запуска задачи в другом потоке изнутри VB6.

Ответ 8

Вот довольно стандартная схема для асинхронной обработки фона в VB6. (Например, в Dan Appleman книга и Microsoft VB6 образцы.) Вы создаете отдельный ActiveX EXE для выполнения работы: таким образом, работа выполняется автоматически в другом потоке, в отдельном процессе (что означает, что вам не нужно беспокоиться о перетаскиваемых переменных).

  • Объект VB6 ActiveX EXE должен выставить событие CheckQuitDoStuff(). Это берет ByRef Boolean, называемый Quit.
  • Клиент вызывает StartDoStuff в объекте ActiveX EXE. Эта процедура запускает таймер в скрытой форме, а немедленно возвращает. Это разблокирует вызывающий поток. Интервал таймера очень короткий, поэтому событие Timer срабатывает быстро.
  • Обработчик событий Timer отключает таймер, а затем снова возвращается к методу DoStuff объекта ActiveX. Это начинает длительную обработку.
  • Периодически метод DoStuff вызывает событие CheckQuitDoStuff. Обработчик события клиента проверяет специальный флаг и устанавливает Quit True, если это необходимо для прерывания. Затем DoStuff прерывает вычисление и возвращает раньше, если Quit is True.

Эта схема означает, что клиент фактически не должен быть многопоточным, так как вызывающий поток не блокируется, пока происходит "DoStuff". Трудная часть заключается в том, чтобы DoStuff поднимал события через соответствующие промежутки времени - слишком долго, и вы не можете уйти, когда захотите: слишком короткий, и вы замедляете DoStuff без необходимости. Кроме того, когда DoStuff завершает работу, он должен выгрузить скрытую форму.

Если DoStuff действительно удастся получить все, что было сделано до того, как будет прервано, вы можете поднять другое событие, чтобы сообщить клиенту, что задание завершено.