2008-09-30 6 views
20

Возможно ли отменить длительный процесс в 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» до «если отменить то ...» есть лучший способ? Прошло некоторое время ...

ответ

28

Нет, вы поняли это правильно, вы определенно хотите, чтобы 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 
7

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

+0

Это VB6, а не vb.net. – GSerg 2008-09-30 23:11:34

+0

Я думаю, что вы были заблокированы, потому что вы сказали, что он «будет лучше использовать отдельный поток». – MusiGenesis 2008-09-30 23:34:33

+0

согласен и исправлен. – TheSoftwareJedi 2008-10-01 00:41:36

8

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

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

+0

Если вы хотите быстро отменить, вы бы хотели называть DoEvents на каждой итерации. – MusiGenesis 2008-09-30 23:15:52

4

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

+0

Хм, как я уже сказал, но проголосовали ... приятно ... – TheSoftwareJedi 2008-09-30 23:21:23

4

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

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

4

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

Обратите внимание, что у этого есть действительно большой недостаток: он обнаружит, ударил ли пользователь 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

3

Вот довольно стандартная схема асинхронной обработки фона в VB6. (Например, это book и Microsoft VB6 samples.) Вы создаете отдельный 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 действительно удалось получить все, что было сделано до того, как оно прервано, вы можете поднять другое событие, чтобы сообщить клиенту, что задание завершено.

 Смежные вопросы

  • Нет связанных вопросов^_^