Что нового

[TreeView] Отловить смену состояния пункта

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Код:
_GUICtrlTreeView_Create


Необходимо среагировать на смену состояния любого пункта ( TreeView_Checkbox ).

На данный момент из кучи выделил два уведомительных кода:
0xFFFFFFFFFFFFFE5F и 0xFFFFFFFFFFFFFE5D ( -417 и -419 ) соответственно. Оба несут с собой lParam с указателем на $tagNMTREEVIEW ( NewSelectedImage, значения 1=снято, 2=поставлено ).

Все бы хорошо - однако эти сообщения не несут с собой указатель на целевой пункт. ;)
Может кто знает иные варианты? Заранее спасибо.

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

$Debug_TV = False ; Проверяет ClassName передаваемый в функции. Установите True и используйте дескриптор от другого элемента, чтобы увидеть как это работает

Global $hTreeView, $iCount = 0

_Main()

Func _Main()

    Local $GUI, $hItem
    Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
    $GUI = GUICreate("Создание TreeView (UDF)", 400, 300)

    $hTreeView = _GUICtrlTreeView_Create($GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)
    GUISetState()

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

    _GUICtrlTreeView_BeginUpdate($hTreeView)
    For $x = 1 To Random(2, 10, 1)
        $hItem = _GUICtrlTreeView_Add($hTreeView, 0, StringFormat("[%02d] Пункт", $x))
        For $y = 1 To Random(2, 10, 1)
            _GUICtrlTreeView_AddChild($hTreeView, $hItem, StringFormat("[%02d] Дочерний", $y))
        Next
    Next
    _GUICtrlTreeView_EndUpdate($hTreeView)

    ; Цикл выполняется, пока окно не будет закрыто
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>_Main


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview
    $hWndTreeview = $hTreeView
    If Not IsHWnd($hTreeView) Then $hWndTreeview = GUICtrlGetHandle($hTreeView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
		Case $hWndTreeview
			If $iCode = -419 Then
				$tNMTREEVIEW = DllStructCreate( $tagNMTREEVIEW, $ilParam )
				_DebugPrint($iCode & " (" & $iCount & ")" & @LF & "--> hWndFrom:" & @TAB & $hWndFrom & @LF & _
						"$iIDFrom=" & $iIDFrom & @LF & _
						"NewChildren=" & DllStructGetData( $tNMTREEVIEW, 'NewChildren' ) & @LF & _
						"NewSelectedImage=" & DllStructGetData( $tNMTREEVIEW, 'NewSelectedImage' ) & @LF )
			EndIf
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func _DebugPrint($s_text)
	$iCount += 1
    ConsoleWrite( @LF &  $s_text )
EndFunc   ;==>_DebugPrint
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
208
CreatoR
Элемент TreeView ( которому было изменено состояние ).

madmasles
Спасибо.

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

$Debug_TV = False ; Проверяет ClassName передаваемый в функции. Установите True и используйте дескриптор от другого элемента, чтобы увидеть как это работает

Global $hTreeView, $iCount = 0

_Main()

Func _Main()

    Local $GUI, $hItem
    Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
    $GUI = GUICreate("Создание TreeView (UDF)", 400, 300)

    $hTreeView = _GUICtrlTreeView_Create($GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)
    GUISetState()

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

    _GUICtrlTreeView_BeginUpdate($hTreeView)
    For $x = 1 To Random(2, 10, 1)
        $hItem = _GUICtrlTreeView_Add($hTreeView, 0, StringFormat("[%02d] Пункт", $x))
        For $y = 1 To Random(2, 10, 1)
            _GUICtrlTreeView_AddChild($hTreeView, $hItem, StringFormat("[%02d] Дочерний", $y))
        Next
    Next
    _GUICtrlTreeView_EndUpdate($hTreeView)

    ; Цикл выполняется, пока окно не будет закрыто
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>_Main


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview, $hItem
    $hWndTreeview = $hTreeView
    If Not IsHWnd($hTreeView) Then $hWndTreeview = GUICtrlGetHandle($hTreeView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
		Case $hWndTreeview
			If $iCode = -419 Then
				$hItem = __TV_GetItemHandle( $hWndTreeview )
				$tNMTREEVIEW = DllStructCreate( $tagNMTREEVIEW, $ilParam )
				_DebugPrint( "Set " & DllStructGetData( $tNMTREEVIEW, "NewSelectedImage" ) & " for " & $hItem & @LF )
			EndIf
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func __TV_GetItemHandle($hTV)
  $tPoint = _WinAPI_GetMousePos(1, $hTV)
  $tTVHTI = _GUICtrlTreeView_HitTestEx($hTV, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))
  $hItem = DllStructGetData($tTVHTI, 'Item')
  Return $hItem
EndFunc

Func _DebugPrint($s_text)
	$iCount += 1
    ConsoleWrite( @LF &  $s_text )
EndFunc   ;==>_DebugPrint
 

CreatoR

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

Код:
Switch $hWndFrom
        Case $hWndTreeview
            If $iCode = $NM_CLICK Then
                $tNMTREEVIEW = DllStructCreate( $tagNMTREEVIEW, $ilParam )
				$hItem = _GUICtrlTreeView_HitTestItem($hWndFrom, _WinAPI_GetMousePosX(True, $hWndFrom), _WinAPI_GetMousePosY(True, $hWndFrom))
                
				_DebugPrint($iCode & " (" & $iCount & ")" & @LF & "--> hWndFrom:" & @TAB & $hWndFrom & @LF & _
                        "$iIDFrom=" & $iIDFrom & @LF & _
                        "$hItem=" & $hItem & @LF & _
                        "NewChildren=" & DllStructGetData( $tNMTREEVIEW, 'NewChildren' ) & @LF & _
                        "NewSelectedImage=" & DllStructGetData( $tNMTREEVIEW, 'NewSelectedImage' ) & @LF )
            EndIf
    EndSwitch
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
firex
У меня Ваш код всегда возвращает NewSelectedImage 1 при изменении состояния Checkbox. :scratch:
Так, вроде, работает:
Код:
#include <GUIConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>

$Debug_TV = False ; Проверяет ClassName передаваемый в функции. Установите True и используйте дескриптор от другого элемента, чтобы увидеть как это работает

Global $hTreeView, $iCount = 0

_Main()

Func _Main()

	Local $GUI, $hItem
	Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
	$GUI = GUICreate('Создание TreeView (UDF)', 400, 300)

	$hTreeView = _GUICtrlTreeView_Create($GUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)
	GUISetState()

	GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

	_GUICtrlTreeView_BeginUpdate($hTreeView)
	For $x = 1 To Random(2, 10, 1)
		$hItem = _GUICtrlTreeView_Add($hTreeView, 0, StringFormat('[%02d] Пункт', $x))
		For $y = 1 To Random(2, 10, 1)
			_GUICtrlTreeView_AddChild($hTreeView, $hItem, StringFormat('[%02d] Дочерний', $y))
		Next
	Next
	_GUICtrlTreeView_EndUpdate($hTreeView)

	; Цикл выполняется, пока окно не будет закрыто
	Do
	Until GUIGetMsg() = $GUI_EVENT_CLOSE
	GUIDelete()
EndFunc   ;==>_Main


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg, $iwParam
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview, $hItem, $s_Txt
	$hWndTreeview = $hTreeView
	If Not IsHWnd($hTreeView) Then $hWndTreeview = GUICtrlGetHandle($hTreeView)

	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
	$iIDFrom = DllStructGetData($tNMHDR, 'IDFrom')
	$iCode = DllStructGetData($tNMHDR, 'Code')
	Switch $hWndFrom
		Case $hWndTreeview
			If $iCode = -419 Then
				$tNMTREEVIEW = DllStructCreate($tagNMTREEVIEW, $ilParam)
				If Not DllStructGetData($tNMTREEVIEW, 'NewChildren') Then
					$hItem = __TV_GetItemHandle($hWndTreeview)
					$s_Txt = _GUICtrlTreeView_GetText($hWndTreeview, $hItem)
					_DebugPrint($hItem & ' Text: "' & $s_Txt & '" Is Checked: ' & (BitAND(DllStructGetData($tNMTREEVIEW, 'OldState'), $TVIS_UNCHECKED) = $TVIS_UNCHECKED) & @LF)
				EndIf
			EndIf
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func __TV_GetItemHandle($hTV)
	$tPoint = _WinAPI_GetMousePos(1, $hTV)
	$tTVHTI = _GUICtrlTreeView_HitTestEx($hTV, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))
	$hItem = DllStructGetData($tTVHTI, 'Item')
	Return $hItem
EndFunc   ;==>__TV_GetItemHandle

Func _DebugPrint($s_text)
	$iCount += 1
	ConsoleWrite('(' & $iCount & ')' & @TAB & $s_text)
EndFunc   ;==>_DebugPrint
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
208
madmasles
На моей машине мой вариант работает, но в любом случае ваш реализован лучше. Еще раз спасибо
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
firex,
Поэкспериментировал со своим примером и нашел еще два способа проверки. Я не знаю, правильно это или нет, но у меня работает. (Windows7x86)
Код:
;~ ...
If Not DllStructGetData($tNMTREEVIEW, 'NewChildren') Then
	ConsoleWrite('OldhItem: ' & DllStructGetData($tNMTREEVIEW, 'OldhItem') & @LF);0x00002000 Checked, 0x00001000 UnChecked
	ConsoleWrite('NewhItem: ' & DllStructGetData($tNMTREEVIEW, 'NewhItem') & @LF);0x00000001 Checked, 0x00000002 UnChecked
EndIf
;~ ...
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
208
madmasles
Сел сегодня за Win7 x64, первый пример с OldState не работает ( постоянно=0 ). На счет второго примера - проходит только OldhItem, а вот HewhItem опять же дает постоянно 0.

Идеально отрабатывает NewSelectedImage( + позволяет исключить лишние уведомления ). Однако странно то, что у вас не работает ( а следовательно - не у всех ). Поищу пока на msdn этот аспект.


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

http://msdn.microsoft.com/en-us/library/windows/desktop/bb775572(v=vs.85).aspx

Код:
Global $tagNMTVSTATEIMAGECHANGING = $tagNMHDR & ";handle hItem; int iOldImage; int iNewImage;"

Switch $iCode
	Case -24
		Local $tNMTVSTATEIMAGECHANGING, $hItem
		; *
		$tNMTVSTATEIMAGECHANGING = DllStructCreate( $tagNMTVSTATEIMAGECHANGING, $lParam )
		$hItem = DllStructGetData( $tNMTVSTATEIMAGECHANGING, "hItem" )
		ConsoleWrite( $hItem & " iNewImage=" & DllStructGetData( $tNMTVSTATEIMAGECHANGING, "iNewImage" ) & @LF)
EndSwitch


Прошу проверить.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
firex,
ИМХО, это самый правильный вариант определения состояния Checkbox у TreeView, только правильная (в соответствии с msdn) структура должна быть примерно такой:
Код:
Global $tagNMTVSTATEIMAGECHANGING = $tagNMHDR & ';handle hItem; int iOldStateImageIndex; int iNewStateImageIndex'
В hItem содержится реальный handle, а проверять можно хоть по iOldStateImageIndex (1-2), хоть по iNewStateImageIndex (2-1). Только надо учесть, что это работает начиная с Vista.
Не могу найти, что это за код -24.
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
208
madmasles
Код:
NM_TVSTATEIMAGECHANGING
 
Верх