Что нового

В чем отличие $EN_UPDATE от $EN_CHANGE в ф-ии WM_COMMAND ?

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Не могу понять различия между :
$EN_UPDATE и $EN_CHANGE
в ф-ии WM_COMMAND .
Вроде обе они отлавливают изменения текста окна :(
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gregaz
EN_CHANGE

Этот код определяет, что пользователь предпринял некоторые
действия, которые, возможно, изменили содержимое текста.
Он посылается после того, как Windows откорректировал
изображение (в отличие от кода EN_UPDATE). Родительское
окно получает этот код через сообщение WM_COMMAND блока
управления.
EN_UPDATE

Этот код показывает, что редактируемый блок управления
будет индицировать измененный текст. Родительское окно
получает этот код через сообщение WM_COMMAND блока
управления. Родительское окно уведомляется после того, как
блок управления сформатировал текст, но перед тем, как
этот текст отобразится на экране. Это дает возможность,
если необходимо, изменить размер окна.
*источник*

В силу недостатка опыта, долго соображал, как увидеть разницу их использования. Вроде так с $EN_UPDATE работает корректнее, чем с $EN_CHANGE:
Код:
#include <GuiConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>

Global $iW_Gui = 160, $iW_Input = 6

$hGui = GUICreate('test', $iW_Gui, 100)
$nInput = GUICtrlCreateInput("", $iW_Gui / 2 - $iW_Input / 2, 10, $iW_Input)
GUICtrlSetLimit(-1, 24)
GUISetState()
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

While 1
	$msg = GUIGetMsg()
	Select
		Case $msg = $GUI_EVENT_CLOSE
			Exit

	EndSelect
WEnd

Func WM_COMMAND($hWnd, $imsg, $iwParam, $ilParam)
	Local $nNotifyCode, $nID, $iLen, _
			$iStep = 6 ; - под мое разрешение экрана.
	$nNotifyCode = BitShift($iwParam, 16)
	$nID = BitAND($iwParam, 0xFFFF)
	;If $nNotifyCode = $EN_CHANGE Then
	If $nNotifyCode = $EN_UPDATE Then
		If Not StringIsDigit(GUICtrlRead($nID)) Then
			GUICtrlSetData($nID, StringRegExpReplace(GUICtrlRead($nID), '[^0-9]', ''))
		EndIf
		$iLen = StringLen(GUICtrlRead($nID))
		$iW_Input = $iStep * ($iLen + 1)
		GUICtrlSetPos($nID, $iW_Gui / 2 - $iW_Input / 2, 10, $iW_Input)
	EndIf
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
$EN_UPDATE работает корректнее, чем с $EN_CHANGE...

Это результат работы функции GUICtrlSetPos(), которая почему-то не форматирует текст (хотя должна). Но пример получился хороший.

Другими словами можно сказать так: сообщения $EN_UPDATE и $EN_CHANGE приходят тогда, когда пользователь изменил текст в Edit/Input, но первое приходит тогда, когда измененный текст еще не отобразился в Edit/Input (но уже присутствует в буфере, т.е. GUICtrlRead() может его прочесть), а второй, тогда, когда измененый текст уже виден. Т.е., последовательность сообщений такая:

...
EN_UPDATE
...
EN_CHANGE
...
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Вот так видно, когда какие события происходят:
Код:
#include <GuiConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>

Global $sCode, $i = 0

$hGui = GUICreate('test', 200, 100)
$nInput = GUICtrlCreateInput('', 50, 10, 100)
GUISetState()
GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')

While 1
	$msg = GUIGetMsg()
	Select
		Case $msg = $GUI_EVENT_CLOSE
			Exit

	EndSelect
WEnd

Func WM_COMMAND($hWnd, $imsg, $iwParam, $ilParam)
	Local $nNotifyCode, $nID, $sText
	$nNotifyCode = BitShift($iwParam, 16)
	$nID = BitAND($iwParam, 0xFFFF)
	$i += 1
	If $nNotifyCode = $EN_UPDATE Then
		$sText = '№ ' & $i & ': ' & 'EN_UPDATE(' & $nNotifyCode & ')' & @CRLF & _
				GUICtrlRead($nID) & @CRLF
	ElseIf $nNotifyCode = $EN_CHANGE Then
		$sText = '№ ' & $i & ': ' & 'EN_CHANGE(' & $nNotifyCode & ')' & @CRLF & _
				GUICtrlRead($nID) & @CRLF & '------------' & @CRLF
	Else
		$sText = $nNotifyCode & @CRLF
	EndIf
	$sCode &= $sText
	ToolTip($sCode, 0, 0)
	If Not Mod($i, 10) Then
		$sCode = ''
	EndIf
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied
madmasles
Спасибо.Кое-что прояснилось.
Вопрос возник из-за необходимости отловить тексты в элементе до и после его изменения.
Для одного элемента это просто решается (предыдущий текст)
А если их несколько ?
[Yashied [?]
но первое приходит тогда, когда измененный текст еще не отобразился в Edit/Input (но уже присутствует в буфере, т.е. GUICtrlRead() может его прочесть), а второй, тогда, когда измененый текст уже виден

И похоже это можно решить с помощью комбинации обработки этих сообщений.
Как ? Надо подумать. :wacko:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
И похоже это можно решить с помощью комбинации обработки этих сообщений.

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

Так?

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

Global $Prev

$hForm = GUICreate('MyGUI', 400, 400)
$Input1 = GUICtrlCreateInput('', 20, 20, 360, 19)
$Input2 = GUICtrlCreateInput('', 20, 50, 360, 19)
$Input3 = GUICtrlCreateInput('', 20, 80, 360, 19)
GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')
GUISetState()

Do
Until GUIGetMsg() = -3

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)

	Local $ID = BitAND($wParam, 0xFFFF)

	Switch $hWnd
		Case $hForm
			Switch BitShift($wParam, 16)
				Case $EN_CHANGE
					Switch $ID
						Case $Input1
							ConsoleWrite('(Input1): ')
						Case $Input2
							ConsoleWrite('(Input2): ')
						Case $Input3
							ConsoleWrite('(Input3): ')
						Case Else
							Return $GUI_RUNDEFMSG
					EndSwitch
					$Data = GUICtrlRead($ID)
					ConsoleWrite('"' & $Prev & '" => "' & $Data & '"' & @CR)
					$Prev = $Data
				Case $EN_SETFOCUS
					$Prev = GUICtrlRead($ID)
			EndSwitch
	EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND


Вот последовательность некоторых сообщений для Edit/Input:

EN_SETFOCUS - приходит при получении фокуса (курсор в поле ввода)
...
EN_CHANGE
EN_UPDATE
...
EN_CHANGE
EN_UPDATE
...
EN_KILLFOCUS - приходит при потере фокуса

ID Input'а находится в младших 2-ух байтах (слове) параметра $wParam.

Код:
BitAND($wParam, 0xFFFF)


Код самого сообщения в старших 2-ух байтах.

Код:
BitShift($wParam, 16)


Хендл Input'а (если нужно) передается в параметре $lParam. Хендл окна, в котором находится данный элемент, передается в $hWnd. $iMsg дублирует значение $WM_COMMAND. Все это справедливо не только для Edit/Input, а для всего сообщения WM_COMMAND.

Т.к. в этом примере всего одно окно $hForm, то проверку

Код:
Switch $hWnd
	Case $hForm
		...
EndSwitch


можно опустить, но я рекомендую всегда проверять окно, которому предназначено данное сообщение.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied
Спасибо за исчерпывающие разъяснения.
А решение - "то,что доктор прописал".

Yashied [?]
Все это справедливо не только для Edit/Input, а для всего сообщения WM_COMMAND
Для снятия последних вопросов по теме :
1.Когда может понадобиться использование этих соообщений ?Не вижу практического предпочтения применения того или другого?
2.Почему эти сообщения отсутствуют для элементов Radio , хотя в WM_COMMAND определяется их $ID ?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Для каждого класса элементов свои сообщения. Для Edit/Input - EN_... (см. EditConstants.au3 - "Notifications"), для кнопок (Button, Check, Radio) - BN_... (см. ButtonConstants.au3 - "Notifications") и т.д., и все они передаются через WM_COMMAND. Более подробную информацию по каждому сообщению и о том, какие именно данные передаются в параметрах wParam и lParam можно почитать в MSDN.

gregaz сказал(а):
Когда может понадобиться использование этих соообщений?

Всегда. Вот еще один пример.

gregaz сказал(а):
Не вижу практического предпочтения применения того или другого?

Если речь идет о EN_UPDATE и EN_CHANGE, то madmasles привел наглядный пример.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied, спасибо . Уже теплее...
Еще один вопрос на посошок :
Для контроля состояния элементов Edit и Radio
корректно ли совместное использование сообщений :
Код:
;..............
Switch $iCode
   Case $EN_CHANGE , $BN_CLICKED
	  ConsoleWrite($iIDFrom& @LF)
EndSwitch
;..............
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
...корректно ли совместное использование сообщений...

Ну подумайте сами... Если действие после "Case" предполагает что-то общее для этих двух сообщений (хотя, я с трудом представляю, что это может быть, разве что ConsoleWrite...), то конечно можно и так написать. Но дабы не путать себя и других, я рекомендую разделять сообщения для элементов разного класса.

Еще кое-что. Все взаимодействие чего-либо с чем-либо в Windows происходит на уровне сообщений. Это основа любого GUI. Например, когда мы нажимаем кнопку, то AutoIt сигнализирует об этом с помощью функции GUIGetMsg(), и мы можем выполнить соответствующие действия. Но, когда нажимается (точнее отпускается) кнопка, происходит ничто иное, как получение от Windows сообщения WM_COMMAND с BN_CLICKED. Таким образом AutoIt узнает о том, что кнопка была нажата, и уже после этого посылает свое сообщение в функцию GUIGetMsg(), благодаря чему, мы и узнаеи об этом событии. Таким образом AutoIt сильно упрощает нам жизнь. Но к сожалению, не все сообщения обрабатываются AutoIt'ом, например для кнопок только BN_CLICKED. А есть ведь и другие, не менее полезные сообщения, например BN_DOUBLECLICKED (посылается при двойном нажатии на кнопку). И вот тогда, когда необходимо задействовать те сообщения, которые не поддерживаются AutoIt'ом по умолчанию, и появляется необходимость писать свои собственные обработчики сообщений, расширяя возможности AutoIt, как в вышеприведенном примере.

К слову, с ListView практически невозможно работать в AutoIt без перехвата дополнительных сообщений.

Уф...

:smile:

P.S

Для более полного представления о сообщениях, посмотрите еще пример для функции _WinAPI_CreateCaret() из библиотеки WinAPIEx.au3 (как раз для Input).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Вот еще один простой пример, заменяющий одинарное нажатие на кнопку двойным.

Код:
#Include <ButtonConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <WinAPI.au3>
#Include <WindowsConstants.au3>

$hForm = GUICreate('MyGUI', 400, 400)
$Button = GUICtrlCreateButton('OK', 160, 365, 80, 25, $BS_NOTIFY)
GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')
GUISetState()

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
		Case $Button
			MsgBox(0, '', 'Button has been pressed!')
	EndSwitch
WEnd

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)

    Local $ID = BitAND($wParam, 0xFFFF), $Code = BitShift($wParam, 16)

    Switch $hWnd
		Case $hForm
			Switch $ID
				Case $Button
					Switch $Code
						Case $BN_CLICKED
							Return 0
						Case $BN_DOUBLECLICKED
							_SendMessage($hWnd, $iMsg, _WinAPI_MakeLong($ID, $BN_CLICKED), $lParam)
					EndSwitch
			EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND
 

SyDr

Сидра
Сообщения
651
Репутация
158
:
/me медитирует на:
Switch $hWnd
Case $hForm
Switch $ID
Case $Button
Switch $Code
Case $BN_CLICKED
:wacko:
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied, спасибо.
Получил общее представление о создании обработчиков событий,
о взаимодействии ф-ий : GUIGetMsg() и WM_COMMAND
Для меня многое прояснилось.
Все разъяснения выполнены простым и понятным языком .
Со "Старым" Новым Годом :beer:
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied
А как поймать предыдущее значение
если текст изменяется не с клавиатуры,
а нажатием кнопок и ф-ией : GUICtrlSetData().
Ведь тогда фокус не устанавливается. ?





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

Я решил это с помощью :

Код:
$Prev = GUICtrlRead()
GUICtrlSetData()

при обработке GUIGetMsg()
Не знаю корректно ли ?
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
И еще выриант (чуть лучше)
Код:
ControlFocus ( "", "", $iID) 
GUICtrlSetData($iID)

Но все это хотелось бы выполнить в WM_COMMAND
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Код:
#Include <EditConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <WindowsConstants.au3>

Global $Prev[3] = ['', '', '']

$hForm = GUICreate('MyGUI', 400, 400)
$Input1 = GUICtrlCreateInput('', 20, 20, 360, 19)
$Input2 = GUICtrlCreateInput('', 20, 50, 360, 19)
$Input3 = GUICtrlCreateInput('', 20, 80, 360, 19)
GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')
GUISetState()

Do
Until GUIGetMsg() = -3

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)

    Local $ID = BitAND($wParam, 0xFFFF), $Code = BitShift($wParam, 16)
	Local $Index

    Switch $hWnd
        Case $hForm
            Switch BitShift($wParam, 16)
                Case $EN_CHANGE
                    Switch $ID
                        Case $Input1
                            ConsoleWrite('(Input1): ')
							$Index = 0
                        Case $Input2
                            ConsoleWrite('(Input2): ')
							$Index = 1
                        Case $Input3
                            ConsoleWrite('(Input3): ')
							$Index = 2
                        Case Else
                            Return $GUI_RUNDEFMSG
                    EndSwitch
                    $Data = GUICtrlRead($ID)
                    ConsoleWrite('"' & $Prev[$Index] & '" => "' & $Data & '"' & @CR)
                    $Prev[$Index] = $Data
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND
 

running-frag

why me?
Сообщения
441
Репутация
60
спасибо, достаточно информативно описано :smile:


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

а если input поле у нас одно (в дочернем GUI) корректен ли будет код? (т.е. наша задача чисто переписать из input в label выполняя функцию)

Код:
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#include <GuiEdit.au3>

$hGUI = 		GUICreate 			('Test', 	250, 	350)
$hEdit =		GUICtrlCreateInput  ("", 		5, 		10, 	240, 25)
$hLabel =		GUICtrlCreateLabel  ("",		100, 	320, 	140, 25, 0x1000)
				GUISetState 		(@SW_SHOW, 	$hGUI)
				
				GUIRegisterMsg 	($WM_COMMAND, "WM_COMMAND")

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

Func _rewrite()
    GUICtrlSetData($hLabel, GUICtrlRead ($hEdit))
	MsgBox (0,0, GUICtrlRead ($hEdit))
EndFunc   ;==>_Change

Func WM_COMMAND($hWnd, $imsg, $wParam, $ilParam)
    ;Local $hWndFrom = 	$ilParam					; ID window (GUI)
    ;Local $iIDFrom = 	BitAND	 ($wParam, 0xFFFF) 	; ID input (handle)
    Local $iCode = 		BitShift ($wParam, 16)		; string (value
    
	Switch $iCode
		Case $EN_CHANGE
			_rewrite ()
	EndSwitch
	#cs
    Switch $hWnd
        Case $hForm
            Switch $iIDFrom
                Case $hEdit
                    Switch $iCode
                        Case $EN_CHANGE
                            _Change()
                    EndSwitch
            EndSwitch
    EndSwitch
	#ce
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND


ps: при таком коде не будет проблем с другими GUI, а именно input'ами?


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

уже разобрался спс за код Yashiedу

при коде выше буду считываться со всех input\edit егегегей :smile: я сообразил, ещё раз спс всем за примеры\код :smile:
 
Верх