Что нового

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

ivsatel

Продвинутый
Сообщения
319
Репутация
84
Здравствуйте.
Использую AutoIt v3.3.8.1

Хочу реализовать отслеживание продолжительности нахождения курсора над иконкой в трее запущенной программы.
Принцип работы такой:
Наведение курсора на иконку запускает функцию которая отобразит окно с данными. Окно с данными закроется по прошествии 8-и секунд или при потере фокуса. Как в данном случае отследить продолжительность нахождения курсора над иконкой? Для вычисления продолжительности данного события.

Код:
#include <GUIConstantsEx.au3>
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=FreeSpace.ico
#AutoIt3Wrapper_Outfile=H:\FreeSpace.exe
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UPX_Parameters=--lzma --no-backup --best --compress-icons=2 --ultra-brute --crp-ms=999999 -f
#AutoIt3Wrapper_Res_Comment=Программа отображения свободного пространства на дисках.
#AutoIt3Wrapper_Res_Description=Программа отображения свободного пространства на дисках.
#AutoIt3Wrapper_Res_Fileversion=1.0.0.1
#AutoIt3Wrapper_Res_LegalCopyright=Copyright © 2013 IvSaTEL
#AutoIt3Wrapper_Res_requestedExecutionLevel=highestAvailable
#AutoIt3Wrapper_Res_Field=CompanyName|IvSatel
#AutoIt3Wrapper_Res_Field=Автор|IvSatel
#AutoIt3Wrapper_Run_Tidy=y
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

Opt("TrayMenuMode", 1 + 2)

TraySetToolTip('Свободное пространство на дисках.')

Global $hGUI, $aArray, $aFreeS[1], $iVisota = @DesktopHeight, $iShiryna = @DesktopWidth, $hTimer, $iCheck

_Wait()

;################################	Функция ожидания

Func _Wait()
	HotKeySet('{Esc}') ;	Назначение пустого значения на горячую клавишу
	While 1
		Sleep(500)
		Switch TrayGetMsg() ;	Ожидание события трея
			Case $TRAY_EVENT_MOUSEOVER
				_GetWindow() ;	Запустить основную функцию при событии трея
		EndSwitch
	WEnd
EndFunc   ;==>_Wait

;################################	Функция ожидания

;################################	Основная функция получения свободного пространства на дисках

Func _GetWindow()
	HotKeySet('{Esc}', '_ProExit') ;	Назначение функции на горячую клавишу

	$aArray = DriveGetDrive("ALL") ;	Получение массива дисков

	If @error Then ;	Если ошибка
		MsgBox(4096, "Ошибка", "Произошла ошибка при запросе дисков.")
		Exit
	EndIf

	For $i = 1 To UBound($aArray) - 1 ;	Цикл получения размеров свободного пространства на найденных дисках

		$iFreeSpace = Round(DriveSpaceFree($aArray[$i]), -1)

		If $iFreeSpace <> '0' Then ;	Если полученный результат не равен нулю то заносим его в массив

			If StringLen($iFreeSpace) >= 4 Then ;	Если количество символов более 3-х то Гигабайты
				$iSize = 'Gb'
			Else
				$iSize = 'Mb'
			EndIf

			_ArrayAdd($aFreeS, 'На диске ' & StringUpper($aArray[$i]) & '\' & ' свободно ' & _
					StringRegExpReplace($iFreeSpace, '(\A\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))', '\1 ') & ' ' & $iSize)

		EndIf
	Next

	;####################	Создание окна с результатами

	$hGUI = GUICreate('Свободное место на дисках', 200, (UBound($aFreeS) * 13) + 5, $iShiryna - 200, $iVisota, $WS_CAPTION, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW))
	$mylist = GUICtrlCreateList("", 5, 5, 190, (UBound($aFreeS) * 13))

	For $i = 1 To UBound($aFreeS) - 1 ;	Заполнение Листвью созданным массивом
		GUICtrlSetData($mylist, $aFreeS[$i])
	Next

	GUISetState(@SW_SHOW)

	For $i = 1 To (UBound($aFreeS) * 13) + 67 ;	Перемещение окна. Всплывание.
		WinMove($hGUI, "", $iShiryna - 205, $iVisota - $i)
	Next

	$hTimer = TimerInit() ;	Установка таймера.

	While 1

		Switch TrayGetMsg() ;	События Tray
			Case $TRAY_EVENT_MOUSEOUT
				GUIDelete($hGUI)
				For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
					_ArrayDelete($aFreeS, $i)
				Next
				_Wait()
				Return
		EndSwitch

		If TimerDiff($hTimer) > 8000 Then ;	Если больше 8-и секунд то выход с очищением массива.
			GUIDelete($hGUI)

			For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
				_ArrayDelete($aFreeS, $i)
			Next

			_Wait()

			Return

		EndIf
		If Not WinActive($hGUI) Then
			GUIDelete($hGUI)
			For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
				_ArrayDelete($aFreeS, $i)
			Next
			_Wait()
			Return
		EndIf
	WEnd

EndFunc   ;==>_GetWindow

;################################	Основная функция получения свободного пространства на дисках

;################################	Функция выхода из программы

Func _ProExit()
	If WinExists($hGUI) Then
		If MsgBox(1 + 32 + 8192, '', 'Завершить работу приложения?') = 1 Then
			GUIDelete($hGUI)
			Exit
		Else
			GUIDelete($hGUI)
			For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
				_ArrayDelete($aFreeS, $i)
			Next
			_Wait()
			Return
		EndIf
	EndIf
EndFunc   ;==>_ProExit
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
ivsatel
Вот несколько ошибок
Код:
ReDim $aFreeS[1] ; Очищение массива

Код:
; If Not ($iFreeSpace = '0') Then ;    Если полученный результат не равен нулю то заносим его в массив
        If $iFreeSpace Then ;    либо так

Когда указывается Gb то не ставится запятая или не отсекается три цифры, а значит измеряемое число остаётся в мегабайтах на деле.
Ну и самая опасная вещь - _Wait и _GetWindow вызывают друг друга, а значит при каждом вызове постоянное неконтролируемое погружение в рекурсивный вызов.

_Wait вызывает _GetWindow, далее если мы выходим из _GetWindow, то возвращаемся в _Wait, но так как мы не выходим из _GetWindow а вызываем из него _Wait, то фактически запускается новая копия функции, а предыдущая так и остаётся висеть ждать своего часа. Но она не дождётся, так как вызванная _Wait снова вызовет _GetWindow и эти копии вызовов не прекращаются.

Все открытые копии функции ожидают возврата данных в точку вызова, но это никогда не происходит, так как новая ветвь порождает ещё больше открытых незавершённых функций.
 
Автор
I

ivsatel

Продвинутый
Сообщения
319
Репутация
84
Спасибо, исправил. Все же вопрос о продолжительности события (если так можно выразится) остался.
 

InnI

AutoIT Гуру
Сообщения
4,923
Репутация
1,432
ivsatel
Из описания я не совсем понял, что вы хотите... но, если я правильно понял код, то у вас две проблемы:
1. Окно не закрывается, когда курсор покидает иконку (у меня не получилось отловить $TRAY_EVENT_MOUSEOUT)
2. Окно открывается повторно, если через 8 секунд курсор всё ещё находится над иконкой
Если так, то можно изобрести способ отслеживания курсора на кнопкой. Вот что у меня получилось (использовал ваш код без правок, предложенных AZJIO, только рекурсию убрал)
Код:
#include <GUIConstantsEx.au3>
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <GuiToolBar.au3>
#include <WinAPI.au3>

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=FreeSpace.ico
#AutoIt3Wrapper_Outfile=H:\FreeSpace.exe
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UPX_Parameters=--lzma --no-backup --best --compress-icons=2 --ultra-brute --crp-ms=999999 -f
#AutoIt3Wrapper_Res_Comment=Программа отображения свободного пространства на дисках.
#AutoIt3Wrapper_Res_Description=Программа отображения свободного пространства на дисках.
#AutoIt3Wrapper_Res_Fileversion=1.0.0.1
#AutoIt3Wrapper_Res_LegalCopyright=Copyright © 2013 IvSaTEL
#AutoIt3Wrapper_Res_requestedExecutionLevel=highestAvailable
#AutoIt3Wrapper_Res_Field=CompanyName|IvSatel
#AutoIt3Wrapper_Res_Field=Автор|IvSatel
#AutoIt3Wrapper_Run_Tidy=y
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

Opt("TrayMenuMode", 1 + 2)

TraySetToolTip('Свободное пространство на дисках.')

Global $hGUI, $aArray, $aFreeS[1], $iVisota = @DesktopHeight, $iShiryna = @DesktopWidth, $hTimer, $iCheck
Global $hToolbar, $tPoint, $tRect

_Wait()

;################################   Функция ожидания

Func _Wait()
	HotKeySet('{Esc}') ;    Назначение пустого значения на горячую клавишу
	While 1
		Sleep(500)
		Switch TrayGetMsg() ;   Ожидание события трея
			Case $TRAY_EVENT_MOUSEOVER
				$tPoint = _WinAPI_GetMousePos() ; Позиция курсора относительно экрана
				$hToolbar = _WinAPI_WindowFromPoint($tPoint) ; панель под курсором
				$tPoint = _WinAPI_GetMousePos(True, $hToolbar) ; Позиция курсора относительно панели
				$tRect = _GUICtrlToolbar_GetButtonRectEx($hToolbar, _GUICtrlToolbar_IndexToCommand($hToolbar, _GUICtrlToolbar_GetHotItem($hToolbar))) ; область кнопки
				_GetWindow() ;  Запустить основную функцию при событии трея
		EndSwitch
	WEnd
EndFunc   ;==>_Wait

;################################   Функция ожидания

;################################   Основная функция получения свободного пространства на дисках

Func _GetWindow()
	HotKeySet('{Esc}', '_ProExit') ;    Назначение функции на горячую клавишу

	$aArray = DriveGetDrive("ALL") ;    Получение массива дисков

	If @error Then ;    Если ошибка
		MsgBox(4096, "Ошибка", "Произошла ошибка при запросе дисков.")
		Exit
	EndIf

	For $i = 1 To UBound($aArray) - 1 ; Цикл получения размеров свободного пространства на найденных дисках

		$iFreeSpace = Round(DriveSpaceFree($aArray[$i]), -1)

		If $iFreeSpace <> '0' Then ;    Если полученный результат не равен нулю то заносим его в массив

			If StringLen($iFreeSpace) >= 4 Then ;   Если количество символов более 3-х то Гигабайты
				$iSize = 'Gb'
			Else
				$iSize = 'Mb'
			EndIf

			_ArrayAdd($aFreeS, 'На диске ' & StringUpper($aArray[$i]) & '\' & ' свободно ' & _
					StringRegExpReplace($iFreeSpace, '(\A\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))', '\1 ') & ' ' & $iSize)

		EndIf
	Next

	;####################   Создание окна с результатами

	$hGUI = GUICreate('Свободное место на дисках', 200, (UBound($aFreeS) * 13) + 5, $iShiryna - 200, $iVisota, $WS_CAPTION, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW))
	$mylist = GUICtrlCreateList("", 5, 5, 190, (UBound($aFreeS) * 13))

	For $i = 1 To UBound($aFreeS) - 1 ; Заполнение Листвью созданным массивом
		GUICtrlSetData($mylist, $aFreeS[$i])
	Next

	GUISetState(@SW_SHOW)

	For $i = 1 To (UBound($aFreeS) * 13) + 67 ; Перемещение окна. Всплывание.
		WinMove($hGUI, "", $iShiryna - 205, $iVisota - $i)
	Next

	$hTimer = TimerInit() ; Установка таймера.

	While 1
		$tPoint = _WinAPI_GetMousePos(True, $hToolbar)
		; Ожидаем выхода курсора за пределы кнопки, окончания времени, потери активности окна
		If Not _WinAPI_PtInRect($tRect, $tPoint) Or TimerDiff($hTimer) > 8000 Or Not WinActive($hGUI) Then
			GUIDelete($hGUI)
			For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
				_ArrayDelete($aFreeS, $i)
			Next
			Do ; Ожидаем выхода курсора за пределы кнопки
				$tPoint = _WinAPI_GetMousePos(True, $hToolbar)
			Until Not _WinAPI_PtInRect($tRect, $tPoint)
			Do ; Очищаем накопившиеся $TRAY_EVENT_MOUSEOVER
			Until TrayGetMsg() = 0
			Return
		EndIf
	WEnd

EndFunc   ;==>_GetWindow

;################################   Основная функция получения свободного пространства на дисках

;################################   Функция выхода из программы

Func _ProExit()
	If WinExists($hGUI) Then
		If MsgBox(1 + 32 + 8192, '', 'Завершить работу приложения?') = 1 Then
			GUIDelete($hGUI)
			Exit
		Else
			GUIDelete($hGUI)
			For $i = 1 To UBound($aFreeS) - 1 ; Очищение массива
				_ArrayDelete($aFreeS, $i)
			Next
			Return
		EndIf
	EndIf
EndFunc   ;==>_ProExit
 
Автор
I

ivsatel

Продвинутый
Сообщения
319
Репутация
84
InnI
Во первых спасибо за идею!
InnI
InnI сказал(а):
Из описания я не совсем понял, что вы хотите...
Основное желание было отловить продолжительность события "нахождения курсора над иконкой в трее"
К примеру, набросок, я понимая его "неправильность", но примерно так:
Код:
Func _Wait()
	HotKeySet('{Esc}') ;    Назначение пустого значения на горячую клавишу
	While 1
		Sleep(500)
		Switch TrayGetMsg() ;   Ожидание события трея
			Case $TRAY_EVENT_MOUSEOVER
				$hTimer = TimerInit()
				While TrayGetMsg() = $TRAY_EVENT_MOUSEOVER
					;MsgBox('', '', TimerDiff($hTimer))
					If TimerDiff($hTimer) > 3000 Then
						$tPoint = _WinAPI_GetMousePos() ; Позиция курсора относительно экрана
						$hToolbar = _WinAPI_WindowFromPoint($tPoint) ; панель под курсором
						$tPoint = _WinAPI_GetMousePos(True, $hToolbar) ; Позиция курсора относительно панели
						$tRect = _GUICtrlToolbar_GetButtonRectEx($hToolbar, _GUICtrlToolbar_IndexToCommand($hToolbar, _GUICtrlToolbar_GetHotItem($hToolbar))) ; область кнопки
						_GetWindow() ;  Запустить основную функцию при событии трея
					Else
						Do ; Очищаем накопившиеся $TRAY_EVENT_MOUSEOVER
						Until TrayGetMsg() = 0
						ExitLoop
					EndIf
				WEnd
		EndSwitch
	WEnd
EndFunc   ;==>_Wait
 

InnI

AutoIT Гуру
Сообщения
4,923
Репутация
1,432
ivsatel [?]
продолжительность события "нахождения курсора над иконкой в трее"
Так?
Код:
#include <Constants.au3>
#include <GuiToolBar.au3>
#include <WinAPI.au3>

HotKeySet("{Esc}", "quit")
Opt("TrayMenuMode", 1 + 2)

While 1
  If TrayGetMsg() = $TRAY_EVENT_MOUSEOVER Then
    ConsoleWrite("over" & @LF)
    ConsoleWrite(OverTime() & @LF)
  EndIf
WEnd

Func OverTime()
  Local $hToolbar, $tPoint, $tRect, $start
  $tPoint = _WinAPI_GetMousePos()
  $hToolbar = _WinAPI_WindowFromPoint($tPoint)
  $tPoint = _WinAPI_GetMousePos(True, $hToolbar)
  $tRect = _GUICtrlToolbar_GetButtonRectEx($hToolbar, _GUICtrlToolbar_IndexToCommand($hToolbar, _GUICtrlToolbar_GetHotItem($hToolbar)))
  $start = TimerInit()
  Do
    $tPoint = _WinAPI_GetMousePos(True, $hToolbar)
  Until Not _WinAPI_PtInRect($tRect, $tPoint)
  Do
  Until TrayGetMsg() = 0
  Return TimerDiff($start)
EndFunc

Func quit()
  Exit
EndFunc
 
Автор
I

ivsatel

Продвинутый
Сообщения
319
Репутация
84
InnI
Да! Спасибо! То, что надо!
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
Ещё "Sleep" вставить в цикл проверки, что курсор на иконке, а то грузит процессор.
 
Верх