Что нового

Определение сфокусированной области в GUICtrlCreateDate

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Как можно определить, где именно сфокусирован курсор на элементе GUICtrlCreateDate (с отображением времени)?
Имеется в виду сфокусирован ли курсор на часах или на минутах.

Вот пример:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <DateTimeConstants.au3>

$hGUI = GUICreate('Test', 200, 200)

$iDate1 = GUICtrlCreateDate('', 10, 10, 80, 20, $DTS_TIMEFORMAT)
GUICtrlSendMsg($iDate1, $DTM_SETFORMATW, 0, 'HH:mm')

$iDate2 = GUICtrlCreateDate('', 10, 40, 80, 20, $DTS_TIMEFORMAT)
GUICtrlSendMsg($iDate2, $DTM_SETFORMATW, 0, 'HH:mm')

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
GUISetState()

While 1
    Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	If @error Then Return $GUI_RUNDEFMSG
	
    Local $iIDFrom = DllStructGetData($tNMHDR, 'IDFrom')
    Local $iCode = DllStructGetData($tNMHDR, 'Code')
	
	If $iCode = $DTN_DATETIMECHANGE Then
		;If it's focused on second field in time element (on minutes), then we need to send {TAB} instead of {RIGHT} (to jump to next element)
		ControlSend($hWnd, '', $iIDFrom, '{RIGHT}')
	EndIf
EndFunc


нужно чтобы при вводе времени фокус всё время переходил далее (если ввели минуты в первом элементе, то нужно сфокусировать следующий элемент).
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
CreatoR [?]
Пользователь может изменить значение разными способами.
С клавиатуры:
- непосредственно ввод цифр (причём достаточно одной цифры)
- нажатие клавиш со стрелками "вверх" или "вниз"
- нажатие клавиш "home" или "end"
- нажатие клавиш "+" или "-" (на цифровой клавиатуре)
Мышью:
- нажатие кнопок элемента "msctls_updown32"

Вопрос. Как определить, что пользователь закончил ввод и можно переключаться на другое поле?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
InnI [?]
Как определить, что пользователь закончил ввод и можно переключаться на другое поле?
В примере есть определение ($DTN_DATETIMECHANGE).
Нужно всего лишь определить в каком участке поля находится курсор, если во втором (на минутах), то вместо RIGHT нужно отправить TAB.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
CreatoR [?]
В примере есть определение
Если пользователь нажмёт "стрелку вверх", то сработает $DTN_DATETIMECHANGE. Но это ещё не значит, что пользователь закончил ввод. Возможно, он хочет нажать эту клавишу/кнопку еще несколько раз, чтобы получить нужное ему значение. С другой стороны, если нажать клавишу, например, "3", то $DTN_DATETIMECHANGE не сработает, хотя пользователю этого может быть достаточно, т.к. контрол сам добавит "0" перед "3" при переключении на другое поле. Вот и получается, что, пытаясь помочь пользователю, фактически, вы можете доставить ему неудобства, т.к. заставляете использовать только цифровой ввод.

определить в каком участке поля находится курсор
Как вариант можно прочитать текст при запуске. Затем при обработке $DTN_DATETIMECHANGE повторно считывать текст, разбивать на два поля и определять, какое изменилось
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <DateTimeConstants.au3>

$hGUI = GUICreate('Test', 200, 200)

$iDate1 = GUICtrlCreateDate('', 10, 10, 80, 20, $DTS_TIMEFORMAT)
GUICtrlSendMsg($iDate1, $DTM_SETFORMATW, 0, 'HH:mm')
$sText1 = GUICtrlRead(-1)

$iDate2 = GUICtrlCreateDate('', 10, 40, 80, 20, $DTS_TIMEFORMAT)
GUICtrlSendMsg($iDate2, $DTM_SETFORMATW, 0, 'HH:mm')
$sText2 = GUICtrlRead(-1)

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    If @error Then Return $GUI_RUNDEFMSG

    Local $iIDFrom = DllStructGetData($tNMHDR, 'IDFrom')

    Local $iCode = DllStructGetData($tNMHDR, 'Code')
    If $iCode = $DTN_DATETIMECHANGE Then
        ;If it's focused on second field in time element (on minutes), then we need to send {TAB} instead of {RIGHT} (to jump to next element)
      Local $sText = GUICtrlRead($iIDFrom)
      Local $aSplit = StringSplit($sText, ":")
      Switch $iIDFrom
        Case $iDate1
          $_ = (StringSplit($sText1, ":")[1] = $aSplit[1]) ? ControlSend($hWnd, '', $iIDFrom, '{TAB}') : ControlSend($hWnd, '', $iIDFrom, '{RIGHT}')
          $sText1 = $sText
        Case $iDate2
          $_ = (StringSplit($sText2, ":")[1] = $aSplit[1]) ? ControlSend($hWnd, '', $iIDFrom, '{TAB}') : ControlSend($hWnd, '', $iIDFrom, '{RIGHT}')
          $sText2 = $sText
      EndSwitch
    EndIf
EndFunc
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
InnI [?]
заставляете использовать только цифровой ввод.
У меня на самом деле есть опция, либо вводить время с переключателя мышкой (типа ползунки как в смартфонах), либо с клавиатуры. Вот если с клавиатуры то там нет кнопок, только ввод.

Как вариант можно прочитать текст при запуске. Затем при обработке $DTN_DATETIMECHANGE повторно считывать текст, разбивать на два поля и определять, какое изменилось
Вариант хороший, но есть проблема, у меня множество таких полей, около 30-ти, и делать такую проверку для всех не очень хочется...
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вот так можно выкрутиться:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <DateTimeConstants.au3>

Global $aDate_Text[50][2]

$hGUI = GUICreate('Test', 200, 320)

For $i = 1 To 10
	_GUICtrlCreateDateEx(Random(1, 23, 1) & ':' & Random(1, 59, 1), 10, 10 + (($i - 1) * 30), 60, 20, $DTS_TIMEFORMAT)
	GUICtrlSendMsg(-1, $DTM_SETFORMATW, 0, 'HH:mm')
Next

GUIRegisterMsg($WM_NOTIFY, '_WM_NOTIFY')
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func _GUICtrlCreateDateEx($sText, $iL, $iT, $iW = Default, $iH = Default, $nStyle = -1, $nExStyle = -1)
	Local $iDate = GUICtrlCreateDate($sText, $iL, $iT, $iW, $iH, $nStyle, $nExStyle)
	
	$aDate_Text[0][0] += 1
	$aDate_Text[$aDate_Text[0][0]][0] = $iDate
	$aDate_Text[$aDate_Text[0][0]][1] = GUICtrlRead($iDate)
	
	Return $iDate
EndFunc

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	If @error Then Return $GUI_RUNDEFMSG
	
	Local $iIDFrom = DllStructGetData($tNMHDR, 'IDFrom')
	Local $iCode = DllStructGetData($tNMHDR, 'Code')
	
	If $iCode = $DTN_DATETIMECHANGE Then
		Local $sText = GUICtrlRead($iIDFrom)
		Local $aSplit = StringSplit($sText, ':')
		
		For $i = 1 To $aDate_Text[0][0]
			If $iIDFrom = $aDate_Text[$i][0] Then
				If StringSplit($aDate_Text[$i][1], ':')[2] <> $aSplit[2] Then
					ControlSend($hWnd, '', $iIDFrom, '{LEFT}')
					Sleep(20)
					
					If $i = $aDate_Text[0][0] Then
						ControlFocus($hWnd, '', $aDate_Text[1][0])
					Else 
						ControlFocus($hWnd, '', $aDate_Text[$i + 1][0])
					EndIf
				Else
					ControlSend($hWnd, '', $iIDFrom, '{RIGHT}')
				EndIf
				
				$aDate_Text[$i][1] = $sText
			EndIf
		Next
	EndIf
EndFunc


но это всё очень не надёжно...
 

angro

Новичок
Сообщения
31
Репутация
1
Может смотреть длину цифры в поле и когда там два знака переносить фокус ?
Всю тему не осилил прочитать ^_^
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
angro [?]
Может смотреть длину цифры в поле и когда там два знака переносить фокус ?
Там всегда будет 5 знаков (NN:NN).
 
Верх