Отмена длительного процесса в 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 …», есть ли лучший способ? Прошло много времени…
- Использовать stream в программировании в vb6
- Лучшая страtagsя перехода с VB6 на .NET
- ReDim Сохраняет multidimensional array в Visual Basic 6
- Любая дешевая или бесплатная среда разработки там для программирования VB6?
- Каков наилучший вариант отображения текста Юникода (иврит и т. Д.) В VB6
- Простая C # DLL - как мне ее назвать из Excel, Access, VBA, VB6?
- Где я должен хранить специальные настройки приложения?
- Исключение кавычек в строке в VB6
- Функция сортировки массива VBA?
- Различные числа от 1 до 10
- Установка VB6 на Windows 7 (или Windows 8) (или Windows 10)
- Свойство Recordset .value
- Остановить Visual Basic 6 от замены моего корпуса
Нет, вы поняли это правильно, вы определенно хотите DoEvents в своем цикле.
Если вы помещаете DoEvents
в свой основной цикл и обнаруживаете, что слишком GetQueueStatus
обрабатываете обработку, попробуйте вызвать функцию GetQueueStatus
(которая намного быстрее, чем DoEvents) Windows API, чтобы быстро определить, нужно ли даже звонить в 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
Нет, вы должны использовать DoEvents, иначе все события пользовательского интерфейса, клавиатуры и таймера будут оставаться в очереди.
Единственное, что вы можете сделать, это вызвать DoEvents один раз на каждые 1000 итераций или таких.
Является ли цикл «for» запущенным в streamе графического интерфейса? Если да, то вам понадобится DoEvents. Вы можете использовать отдельный stream, и в этом случае DoEvents не требуется. Вы можете сделать это в VB6 (не просто).
Вы можете запустить его на отдельном streamе, но в VB6 это королевская боль. DoEvents должны работать. Это взломать, но тогда и VB6 (10-летний ветеран VB говорит здесь, поэтому не меняйте меня).
Разделите задачу на длительную работу на кванты. Такие задачи часто управляются простым циклом, поэтому разрезайте его на 10, 100, 1000 и т. Д. Итераций. Используйте элемент управления таймером, и каждый раз, когда он срабатывает, выполняет часть задачи и сохраняет свое состояние во время движения. Для начала настройте начальное состояние и включите таймер. По завершении отключите таймер и обработайте результаты.
Вы можете «настроить» это, изменив количество работы на квант. В обработчике событий Timer вы можете проверить «отменить» и остановиться по мере необходимости. Вы можете сделать все это аккуратно, объединив рабочую нагрузку и таймер в UserControl с событием Completed.
Это хорошо работает для меня, когда мне это нужно. Он проверяет, нажал ли пользователь клавишу эвакуации, чтобы выйти из цикла.
Обратите внимание, что у него действительно большой недостаток: он обнаружит, что пользователь ударил ключ 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
EDIT получается, что статья MSDN ошибочна, и техника НЕ РАБОТАЕТ 🙁
Вот статья об использовании компонента .NET BackgroundWorker для запуска задачи в другом streamе из VB6.
Вот довольно стандартная схема асинхронной фоновой обработки в VB6. (Например, это в книге Дэна Эпплмана и в образцах Microsoft VB6.) Вы создаете отдельный ActiveX EXE для выполнения работы: таким образом, работа выполняется автоматически в другом streamе в отдельном процессе (что означает, что вам не нужно беспокоиться о перетаскиваемые переменные).
- Объект VB6 ActiveX EXE должен выставить событие CheckQuitDoStuff (). Это берет ByRef Boolean, называемый Quit.
- Клиент вызывает StartDoStuff в объекте ActiveX EXE. Эта процедура запускает таймер по скрытой форме и немедленно возвращается . Это разблокирует вызывающий stream. Интервал таймера очень короткий, поэтому событие Timer срабатывает быстро.
- Обработчик событий Timer отключает таймер, а затем снова возвращается к методу DoStuff объекта ActiveX. Это начинает длительную обработку.
- Периодически метод DoStuff вызывает событие CheckQuitDoStuff. Обработчик события клиента проверяет специальный флаг и устанавливает Quit True, если это необходимо для прерывания. Затем DoStuff прерывает вычисление и возвращает раньше, если Quit is True.
Эта схема означает, что клиент фактически не должен быть многопоточным, так как вызывающий stream не блокируется, пока происходит «DoStuff». Трудная часть заключается в том, чтобы DoStuff поднимал события через соответствующие промежутки времени – слишком долго, и вы не можете уйти, когда захотите: слишком короткий, и вы замедляете DoStuff без необходимости. Кроме того, когда DoStuff завершает работу, он должен выгрузить скрытую форму.
Если DoStuff действительно сумеет получить все, что было сделано до того, как будет прервано, вы можете поднять другое событие, чтобы сообщить клиенту, что задание завершено.