Что нового

[Элементы GUI] Как организовать реакцию GUI в режиме GUIOnEventMode если:

pgs2

Новичок
Сообщения
29
Репутация
0
Есть такой вот скрипт:
Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#Include <date.au3>
#include <GuiEdit.au3>


Opt("WinWaitDelay",100)
Opt("WinTitleMatchMode",2)
Opt("WinDetectHiddenText",1)
Opt("MouseCoordMode",2)
Opt("PixelCoordMode",2)
Opt("GUIOnEventMode", 1)
AutoItSetOption ( "GUICloseOnESC", 1 )
Global $mainwindow, $h_Exit, $h_Start, $h_Pause, $h_Stop

$mainwindow = GUICreate ("mainwindow", 360, 430)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
$EditScreen = GUICtrlCreateEdit (" ", 2, 2, 357, 404, BitOR($ES_READONLY, $WS_EX_STATICEDGE, $WS_VSCROLL, $ES_AUTOVSCROLL))

; Digit's buttons

$h_Exit = GUICtrlCreateButton("Выход", 313, 409, 45, 20)
GUICtrlSetOnEvent($h_Exit, "CLOSEClicked")
$h_Stop = GUICtrlCreateButton("Стоп", 219, 409, 45, 20)
GUICtrlSetOnEvent($h_Stop, "h_Stop")
$h_Pause = GUICtrlCreateButton("Пауза", 172, 409, 45, 20)
GUICtrlSetOnEvent($h_Pause, "h_Pause")
$h_Start = GUICtrlCreateButton("Старт", 125, 409, 45, 20)
GUICtrlSetOnEvent($h_Start, "h_Start")
GUISetState()

While 1

WEnd

Func CLOSEClicked()
    Exit
EndFunc

Func h_Stop()

EndFunc

Func h_Pause()

EndFunc

Func h_Start()
   Go()
EndFunc

Func Go()
Local $A
While 1
$A += 1
$A -=1
WEnd
EndFunc

В примере Go() я упростил, но суть в общем та же. Функция проверяет цвет точек и кликает, в бесконечном цикле. Причем делает это в реальном времени и если приостановить в каком то месте, то какие то события будут пропущены и не обработаны.
В таком виде скрипт после старта можно остановить только через иконку в трее.
Как организовать реакцию GUI, что б можно было пользоваться кнопками интерфейса?
Как осуществлять остановку для перезапуска и паузу для смены настроек.
И может попутно подскажете, как бороться с тем, что все клики работают только если окно активно. Пользуюсь:
Код:
ControlClick ( $titl, "", $klass , "left" , 1, $k_cdx, $k_cdy)
; определяю цвет точки
$c = PixelGetColor ($posX, $posY)

Как продолжать кликать и определять цвет, если окно перестанет быть активным?
 

killbond

Осваивающий
Сообщения
96
Репутация
32
Как гласит хелп:
В режиме OnEvent вместо постоянного опроса GUI применяется другой способ реагирования на возникающие события. Реакцией GUI на событие является временная остановка текущей обработки сценария (прерывание) и вызов заранее созданных функций сценария, единственным назначением которых является обработка некоторого события. После завершения обработки события сценарий продолжает прерванную обработку.

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

Лучше такой вариант:

Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#Include <date.au3>
#include <GuiEdit.au3>


Opt("WinWaitDelay",100)
Opt("WinTitleMatchMode",2)
Opt("WinDetectHiddenText",1)
Opt("MouseCoordMode",2)
Opt("PixelCoordMode",2)
AutoItSetOption ( "GUICloseOnESC", 1 )
Global $mainwindow, $h_Exit, $h_Start, $h_Pause, $h_Stop, $Started = 0

$mainwindow = GUICreate ("mainwindow", 360, 430)
$EditScreen = GUICtrlCreateEdit (" ", 2, 2, 357, 404, BitOR($ES_READONLY, $WS_EX_STATICEDGE, $WS_VSCROLL, $ES_AUTOVSCROLL))

; Digit's buttons

$h_Exit = GUICtrlCreateButton("Выход", 313, 409, 45, 20)
$h_Stop = GUICtrlCreateButton("Стоп", 219, 409, 45, 20)		; Кнопку паузы лучше убрать... лишней путаницы не будет
$h_Start = GUICtrlCreateButton("Старт", 125, 409, 45, 20)
GUISetState()

Do
	_Survey ()
	If $Started then 
		Go()
	EndIf
Until GUIGetMsg() = $GUI_EVENT_CLOSE
Exit

Func _Survey () ; Опрос вынесен в отдельную функцию для краткости, потому что он должен вызываться из 2-ух мест
	Switch GUIGetMsg()
		case $h_Exit
			Exit
		case $h_Start
			$Started = Not $Started
			If $Started Then
				GUICtrlSetData ( $h_Start, "Пауза" )
			Else 
				GUICtrlSetData ( $h_Start, "Старт" )
			EndIf
		case $h_Stop

	EndSwitch
EndFunc

Func Go()
	Local $A = 0
	While 1
	if $Started then ; Благодаря этому, при паузе никакие события не пропускаются
		ToolTip($A,0,0)
		$A += 1
	EndIf
	_Survey ()
	WEnd
EndFunc


Но это, с моей точки зрения, колдунство над кодом, его следует использовать только если объявление локальных переменных в функции Go обязательно, если же не обязательно, то вот вариант еще лучше:

Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#Include <date.au3>
#include <GuiEdit.au3>

Opt("WinWaitDelay",100)
Opt("WinTitleMatchMode",2)
Opt("WinDetectHiddenText",1)
Opt("MouseCoordMode",2)
Opt("PixelCoordMode",2)
AutoItSetOption ( "GUICloseOnESC", 1 )
Global $mainwindow, $h_Exit, $h_Start, $h_Pause, $h_Stop, $bStarted = 0, $A

$mainwindow = GUICreate ("mainwindow", 360, 430)
$EditScreen = GUICtrlCreateEdit (" ", 2, 2, 357, 404, BitOR($ES_READONLY, $WS_EX_STATICEDGE, $WS_VSCROLL, $ES_AUTOVSCROLL))

; Digit's buttons

$h_Exit = GUICtrlCreateButton("Выход", 313, 409, 45, 20)
$h_Stop = GUICtrlCreateButton("Стоп", 219, 409, 45, 20)     ; Кнопку паузы лучше убрать... лишней путаницы не будет
$h_Start = GUICtrlCreateButton("Старт", 125, 409, 45, 20)
GUISetState()

While 1
	Switch GUIGetMsg()
        case $h_Exit
            Exit
        case $h_Start
            $bStarted = Not $bStarted
            If $bStarted Then
                GUICtrlSetData ( $h_Start, "Пауза" )
            Else 
                GUICtrlSetData ( $h_Start, "Старт" )
            EndIf
        case $h_Stop
			
		case $GUI_EVENT_CLOSE
			Exit
    EndSwitch
	if $bStarted then ; Благодаря этому, при паузе никакие события не пропускаются
		Go ()
    EndIf
WEnd

Func Go ()
	ToolTip($A,0,0)
	$A += 1
EndFunc


Вопрос к знатокам: при написании вышеизложенного примера, столкнулся с такой проблемой - если вместо конструкции While 1 ... Wend употребить конструкцию Do ... Until GUIGetMsg() = $GUI_EVENT_CLOSE то GUI реагирует не на каждое нажатие элемента, почему так?

Про клики в неактивное окно: как я понял из этой темы, клик в неактивное окно можно сделать простым ControlClick, но при этом важно указать хендл контрола, вот пример на обычном сапере :smile:

Код:
$sTitle = 'Сапер'
$X = Random( 15, 495 ) 
$Y = Random( 105, 360 ) 

$hWnd = WinGetHandle($sTitle)
ControlClick ( $sTitle, "", $hWnd, 'left', 1, $X, $Y )


Хм... какова вероятность, что сей "игрок" не подорвется на мине? ;D
 
Автор
P

pgs2

Новичок
Сообщения
29
Репутация
0
У меня клик идет по флешу, а не по окну, по этому
Код:
ControlClick ( $titl, "", $klass , "left" , 1, $k_cdx, $k_cdy)

именно $klass так как флеш это как кнопка или поле ввода. Или я что то путаю :smile:
Хотя вроде клики у меня идут и в неактивном окне. А вот PixelGetColor неактивное окно не видит. Вот к PGC бы что нить прикрутить чтоб неактивное окно видеть начал...
То что в цикл придеться опрос вставлять, я то же к такому выводу пришел, другого не придумать, а жаль. Опрос будет подтормаживать цикл в функции Go(). Еще такой вопросик: методы MessageLoop и OnEvent взаимоисключаемые? Просто реакцию многих элементов GUI удобнее ловить OnEvent. Или можно ли в функцию Go() передавать события OnEvent, там внутри функции делать опрос и если произошло событие, выходить из функции через Return ?
 
Автор
P

pgs2

Новичок
Сообщения
29
Репутация
0
Опрос внутри функции мне никак не осуществить.... Чтоб нормально откликались кнопки опрос надо производить раза 2 в секунду( а лучше чаще) внутри функции 4 вложеных и несколько циклов с выходом по условию приблизительно так:
Код:
Func Go()
For
 ; 999 максимальных повторов (сюда попадает раз в 1-3 минуты)
                While
	         Sleep(50); выход по условию (секунд 5)
                WEnd
                While 
		Sleep(50); выход по условию (секунд 5)
	    WEnd
   While
      ;(сюда попадает раз в 25-30 секунд)
        For
         ;(сюда попадает раз в 3-7 секунд)
            While
              ;выход по условию (крутиться 2-4 секунды)
            WEnd
        Next 
   WEnd 
              While
                 Sleep (50) ; выход по условию (секунд 5)
              WEnd 
              While 
	      Sleep (50); выход по условию (секунд 5)
              WEnd
              While
              Sleep (50); выход по условию (секунд 15-20)
              WEnd
              While
              Sleep (50); выход по условию (секунд 5)
              WEnd 
              While 
	  Sleep (50); выход по условию (секунд 5)
              WEnd
              While
              Sleep (50); выход по условию (секунд 5)
              WEnd
Next

как делать опрос событий во вложеных циклах я не представляю, это надо будет через строчку вызывать функцию опроса? А местами есть спец. паузы от 1 до 3 секунд, в этот момент кнопки будут вообще недоступны. Вариант с опросом не нравиться... Хотя при всем при этом, закрыть скрипт или поставить на паузу, а затем продолжить с момента остановки, доступно через иконку в трее. И как это работает? Я хочу такой же код для своего скрипта!
То же самое и с определением цвета точки в неактивном окне. Autoit Window Info прекрасно определяет цвета в точке как раз в неактивном окне !!! Я хочу такой же код для своего скрипта!
 

killbond

Осваивающий
Сообщения
96
Репутация
32
У меня клик идет по флешу, а не по окну, по этому

А флеш чем тебе не часть окна? Зачем их обижаешь? :smile: По любому элементу GUI (и не только, кстати) в Windows можно кликнуть (хоть в скрытом, хоть не в скрытом окне). Только нужно правильно указать хендл контрола. Ели это кнопка или поле ввода, то дастаточно собрать данные о нем с помощью WIT, или, если он ничего толкового не выдает, в качестве хендла можно указать само поле, где проигрывается флеш.

То что в цикл придеться опрос вставлять, я то же к такому выводу пришел, другого не придумать, а жаль.

Ну или тогда попробуй избавиться от функции Go таким образом:

Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#Include <date.au3>
#include <GuiEdit.au3>


Opt("WinWaitDelay",100)
Opt("WinTitleMatchMode",2)
Opt("WinDetectHiddenText",1)
Opt("MouseCoordMode",2)
Opt("PixelCoordMode",2)
Opt("GUIOnEventMode", 1)
AutoItSetOption ( "GUICloseOnESC", 1 )
Global $mainwindow, $h_Exit, $h_Start, $h_Pause, $h_Stop, $bStarted = 0, $A = 0

$mainwindow = GUICreate ("mainwindow", 360, 430)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
$EditScreen = GUICtrlCreateEdit (" ", 2, 2, 357, 404, BitOR($ES_READONLY, $WS_EX_STATICEDGE, $WS_VSCROLL, $ES_AUTOVSCROLL))

; Digit's buttons

$h_Exit = GUICtrlCreateButton("Выход", 313, 409, 45, 20)
GUICtrlSetOnEvent($h_Exit, "CLOSEClicked")
$h_Stop = GUICtrlCreateButton("Стоп", 219, 409, 45, 20)
GUICtrlSetOnEvent($h_Stop, "h_Stop")
$h_Pause = GUICtrlCreateButton("Пауза", 172, 409, 45, 20)
GUICtrlSetOnEvent($h_Pause, "h_Pause")
$h_Start = GUICtrlCreateButton("Старт", 125, 409, 45, 20)
GUICtrlSetOnEvent($h_Start, "h_Start")
GUISetState()

While 1
	If $bStarted Then
		$A += 1
		ToolTip($A,0,0)
	EndIf
WEnd

Func CLOSEClicked()
    Exit
EndFunc

Func h_Stop()

EndFunc

Func h_Pause()
	h_Start()
EndFunc

Func h_Start()
   $bStarted = NOT $bStarted
EndFunc


Опрос будет подтормаживать цикл в функции Go()

Да, но тебе это даже незаметно будет

Еще такой вопросик: методы MessageLoop и OnEvent взаимоисключаемые?

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


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

Как пишут на официальном форуме, PixelGetColor не работает для свернутого окна. Знатоки, выручайте: как узнать цвет пикселя в неактивном окне? (и в свернутом тоже) :smile:
 
Автор
P

pgs2

Новичок
Сообщения
29
Репутация
0
Да, если от функции избавиться, а ее тело просто запихать в цикл и выполнять по условию старта, все становиться намного проще и приятнее. Активация окна при каждом обращении к PixelGetColor съедает кучу времени и стабильно отловить цвет точки, который появляеться на 0.2 - 0.4 сек., не получаеться. Да и вообще бесит, когда окно управление перехватывает :smile:
Спасибо! Люблю простые решения сложных задач ;D
Решение найдено, а про определение цвета точки в неактивном окне, выношу в отдельный вопрос.
 
Верх