Что нового

Как остановить цикл While по кнопке?

Вовчик55

Новичок
Сообщения
57
Репутация
0
Допустим есть какой-то цикл While 1, который запускается с кнопки Button1. Остановить этот цикл можно лишь через трей. Если же повесить на кнопку Button2 Exit - то выход будет произведён лишь после того как весь цикл While 1 выполнится, а если нажать в трее Выход - то всё моментально закрывается

Код:
TrayCreateItem("Выход")
TrayItemSetOnEvent(-1, "On_Exit")

TraySetState()

$Button1 = GUICtrlCreateButton("Пуск")
$Button2 = GUICtrlCreateButton("Стоп")

While 1
Case $GUI_EVENT_CLOSE
	Exit
Case $Button1
        While 1
            ;Сам цикл
        WEnd 
Case $Button2 ;Стоп
        Exit
WEnd

Func On_Exit()
    Exit
EndFunc


Хотелось бы чтобы по кнопке Стоп либо прекращался сам цикл, либо происходил выход (не ждя окончания самого цикла)
 

SemEMP

Знающий
Сообщения
42
Репутация
7
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 325, 161, 309, 272)
$Button1 = GUICtrlCreateButton("Button1", 80, 24, 75, 25)
$Button2 = GUICtrlCreateButton("Button2", 80, 56, 75, 25)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

		Case $Button1
			$pid=run('projFunc.exe')

		Case $Button2
			ProcessClose($pid)
	EndSwitch
WEnd

где в скомпилированном файле projFunc.exe содержится твоя функция, или например для теста моя
Код:
ProgressOn("Измеритель прогресса", "Увеличивается каждую секунду", "0 процентов") ; создаёт окно прогресса.

for $i=1 to 100
	 ProgressSet($i, $i & " процентов")
	 Sleep(100)
Next
Exit
 
Автор
Вовчик55

Вовчик55

Новичок
Сообщения
57
Репутация
0
Хотелось бы без дополнительных файлов, в одном коде. Или это невозможно?
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Вовчик55
Код:
HotKeySet('{ESC}', '_Stop')

$Trg = 0
...
	Case $Button1
		While 1
			; если получен сигнал от кнопки-2 на выпрыг или тригер является True, то
			If GUIGetMsg() = $Button2 Or $Trg Then ExitLoop
			; ... тут какой-то код
		WEnd
	Case $Button2 ;Стоп
		Exit


Func _Stop()
	$Trg = 1
EndFunc
 
Автор
Вовчик55

Вовчик55

Новичок
Сообщения
57
Репутация
0
AZJIO, таким образом сразу не происходит выход из программы, либо остановка While - а сначала ждёт завершение одного цикла, а затем уже будет выход. Хотелось бы чтобы моментально после нажатия кнопки происходил либо выход, либо останов цикла (потому что цикл бывает очень длинный до 2-5 мин) :-[
Вообще как-то возможно в AutoIt приостановить/завершить цикл посреди работы кнопкой а не через трей или горячую клавишу? Потому что во время выполнения цикла ничего не работает: ни крестик закрытия окошка, ни кнопка Стоп - только получается закрыть через трей :(

Ну для наглядности допустим такой код:
(из этого слипа не выйдешь, пока не нажмёшь в трее Выход)
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 3)
TrayCreateItem("Выход")
TrayItemSetOnEvent(-1, "On_Exit")

$Okno = GUICreate("Окно", 315, 182, 192, 124)
$Button1 = GUICtrlCreateButton("Пуск", 48, 80, 75, 25)
$Button2 = GUICtrlCreateButton("Стоп", 168, 80, 75, 25)
GUISetState(@SW_SHOW)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            Exit
        Case $Button1
            While 1
			    If GUIGetMsg() = $Button2 Then ExitLoop
                Sleep(1000*50)
            WEnd
    EndSwitch
WEnd

Func On_Exit()
    Exit
EndFunc
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 3)
TrayCreateItem("Выход")

$Okno = GUICreate("Окно", 315, 182, 192, 124)
$iLabel = GUICtrlCreateLabel('', 20, 20, 100, 20)
$Button1 = GUICtrlCreateButton("Пуск", 48, 80, 75, 25)
$Button2 = GUICtrlCreateButton("Стоп", 168, 80, 75, 25)
GUISetState(@SW_SHOW)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            AdlibUnRegister()
        Case $Button1
            AdlibRegister('Loop', 1)
    EndSwitch
WEnd

Func Loop()
	Static $icount
	GUICtrlSetData($iLabel, $icount)
	$icount += 1
EndFunc
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Вовчик55 [?]
Потому что во время выполнения цикла ничего не работает: ни крестик закрытия окошка, ни кнопка Стоп
Справшивается для чего я сделал опрос и внутри цикла, от которого не ожидалось что он будет реагировать. Конечно не будет если не опрашивать события. А если опрашивать то будет. Только проблема другая, сам опрос замедляет работу цикла.

AZJIO, таким образом сразу не происходит выход из программы
Конечно не происходит, ведь по условию:
[?]
Хотелось бы чтобы по кнопке Стоп либо прекращался сам цикл, либо происходил выход (не ждя окончания самого цикла)
либо выход либо остановка цикла. Ведь изначально не оговоривалось что нужен только выход. ExitLoop заменить на Exit разве проблема?

[?]
Вообще как-то возможно в AutoIt приостановить/завершить цикл посреди работы кнопкой а не через трей или горячую клавишу?
ДА я кнопкой и делал.
Код:
Sleep(1000*50)
Цикл обычно выполняется многими мелкими командами, между которыми можно делать проверки, а Sleep это нереальная команда, это не тот случай, хотя и её прервать можно. К примеру у меня в программе 10 минут ищутся файлы по диску, но запрос между очередным файлом микросекунды, соответсвенно я с точностью в микросекунды могу прервать цикл, потому что проверяю разрешающий следующий шаг триггер. Если тригер переключен, то цикл завершается.

Ну для наглядности допустим такой код:
(из этого слипа не выйдешь, пока не нажмёшь в трее Выход)
AdlibRegister уже предложили но я в своей программе не стал бы при поиске и замене прерывать запись файла с помощью AdlibRegister, поэтому я выброл триггер. Покажите реальную ситуацию а не надуманную.




Добавлено:
Сообщение автоматически объединено:

Вовчик55
Раз уж у вас не реальный пример, держите соответсвующее нереальное решение. Как говорится какой вопрос, такой и ответ, но работает кнопка всё как вы просили, и ждёт 50 сек, до следующего шага While. То есть если не не прервать через 50 сек сменит заголовок.
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 3)
TrayCreateItem("Выход")
TrayItemSetOnEvent(-1, "On_Exit")

$Okno = GUICreate("Окно", 315, 182, 192, 124)
$Button1 = GUICtrlCreateButton("Пуск", 48, 80, 75, 25)
$Button2 = GUICtrlCreateButton("Стоп", 168, 80, 75, 25)
GUISetState(@SW_SHOW)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $Button2
			Exit
		Case $Button1
			While 1
				WinSetTitle($Okno, '', 'Цикл запущен')
				For $i = 1 To 500
					If GUIGetMsg() = $Button2 Then Exit
					Sleep(10)
				Next
				WinSetTitle($Okno, '', 'Шаг1')
			WEnd
	EndSwitch
WEnd

Func On_Exit()
	Exit
EndFunc   ;==>On_Exit
 
Автор
Вовчик55

Вовчик55

Новичок
Сообщения
57
Репутация
0
Вот реальный пример, нужно остановить набор текста:
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 3)
TrayCreateItem("Выход")
TrayItemSetOnEvent(-1, "On_Exit")

$Tekst='Текст для набора'

$Okno = GUICreate("Окно", 315, 182, 192, 124)
$Button1 = GUICtrlCreateButton("Пуск", 48, 80, 75, 25)
$Button2 = GUICtrlCreateButton("Стоп", 168, 80, 75, 25)
GUISetState(@SW_SHOW)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            Exit
        Case $Button1
            While 1
                Send($Tekst,1)
            WEnd
    EndSwitch
WEnd

Func On_Exit()
    Exit
EndFunc


Текста оочень много и потому бывает нужно остановить/закрыть/приостановить набор (неважно что именно, главное остановить печать ;D)
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Вовчик55
Ну сама идея остаётся таже, что я предложил изначально. Только вместо Send лучше использовать ControlSend, чтобы при нажатии кнопки не высылать Send на кнопку.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
если нужно остановить функцию и сделать выход из программы по нажатию кнопки в окне программы
Код:
$Form1 = GUICreate("Form1", 491, 128, 360, 419)
$Progress1 = GUICtrlCreateProgress(24, 32, 422, 17)
$Button1 = GUICtrlCreateButton("Start", 40, 72, 75, 25)
$Button2 = GUICtrlCreateButton('Stop', 150, 72, 75, 25)
GUISetState(@SW_SHOW)
GUIRegisterMsg(0x0111, 'WM_COMMAND')
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case -3
			Exit
		Case $Button1
			_progress()
	EndSwitch
WEnd

Func _progress()
	$i = 1
	While 1
		GUICtrlSetData($Progress1, $i)
		If $i = 100 Then
			GUICtrlSetData($Progress1, '')
			ExitLoop
		EndIf
		$i += 1
		Sleep(100)
	WEnd
EndFunc   ;==>_progress


Func WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
	Local $nNotifyCode = BitShift($wParam, 16)
	Local $nID = BitAND($wParam, 0xFFFF)
	Switch $nNotifyCode
		Case 0
			Switch $nID
				Case $Button2
					Exit
			EndSwitch
	EndSwitch
	Return 'GUI_RUNDEFMSG'
EndFunc   ;==>WM_COMMAND
но при этом закроется вся программа. если нужно только закрыть цикл, вызванные через кнопку старт, то в самом цикле нужно делать проверку на существование команды. при длинном цикле эту проверку нужно будет ставить в нескольких местах. желательно там, где идет основная обработка.
пример с завершение функции без выхода из программы
Код:
Global $ExitFunc = 0
$Form1 = GUICreate("Form1", 491, 128, 360, 419)
$Progress1 = GUICtrlCreateProgress(24, 32, 422, 17)
$Button1 = GUICtrlCreateButton("Start", 40, 72, 75, 25)
$Button2 = GUICtrlCreateButton('Stop', 150, 72, 75, 25)
GUISetState(@SW_SHOW)
GUIRegisterMsg(0x0111, 'WM_COMMAND')
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case -3
			Exit
		Case $Button1
			_progress()
			MsgBox(0, '', 'Выход из функции')
		Case $Button2
	EndSwitch
WEnd

Func _progress()
	$i = 1
	While 1
		If $ExitFunc = 1 Then
			GUICtrlSetData($Progress1, '')
			$ExitFunc = 0
			ExitLoop; или использовать Return
		EndIf
		GUICtrlSetData($Progress1, $i)
		If $i = 100 Then
			GUICtrlSetData($Progress1, '')
			ExitLoop
		EndIf
		$i += 1
		Sleep(100)
	WEnd
EndFunc   ;==>_progress


Func WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
	Local $nNotifyCode = BitShift($wParam, 16)
	Local $nID = BitAND($wParam, 0xFFFF)
	Switch $nNotifyCode
		Case 0
			Switch $nID
				Case $Button2
					$ExitFunc = 1

			EndSwitch
	EndSwitch
	Return 'GUI_RUNDEFMSG'
EndFunc   ;==>WM_COMMAND
 

ivsatel

Продвинутый
Сообщения
319
Репутация
84
Не понятно почему проверка срабатывает только при назначении горячей клавиши:
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <File.au3>

Global $c = '0', $HKSRUN, $HKSPAUSE

Dim $aRecords[1]

$HKSRUN = HotKeySet("{F11}", "_WRT")
$HKSPAUSE = HotKeySet("{F10}", "_NULL")

If Not _FileReadToArray(@ScriptDir & "\Text.txt", $aRecords) Then
    MsgBox(4096, "Ошибка", " Ошибка чтения файла в массив     Ошибка = " & @error)
    Exit
EndIf

$Okno = GUICreate("Окно", 700, 400)
$iEdit = GUICtrlCreateEdit("", 1, 1, 700, 340, $WS_VSCROLL)
$Button1 = GUICtrlCreateButton("Пуск", 50, 350, 100)
$Button2 = GUICtrlCreateButton("Стоп", 150, 350, 100)

GUISetState(@SW_SHOW)

While 1
	$nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button1
			$c = '0'
			_WRT()
		Case $Button2
			$c = '1'
			_NULL()
		Case $HKSRUN
			$c = '0'
			_WRT()
		Case $HKSPAUSE
			$c = '1'
			_NULL()
    EndSwitch
WEnd

Func _WRT()
	For $i = 1 To UBound($aRecords) - 1
			Sleep(50)
		If $c = '0' Then
			ControlFocus($Okno, "", '[CLASS:Edit; INSTANCE:1]')
			Send($aRecords[$i])
			Send(@LF)
		Else
			$c = ''
			Return
		EndIf
	Next
	$c = ''
EndFunc

Func _NULL()
Sleep(100)
$c = ''
Return
EndFunc
А отключив клавиши, проверка в цикле как будто отсутствует...
Так же не происходит назначение переменной в Case если в глобальном объявлении задать пустое содержимое.
 
Верх