- Offizieller Beitrag
Das Thema klingt banal, ist programmtechnisch auch banal. Aber das Problem kommt beim Klick.
Im Normalfall wird beim Klick auf eine Checkbox nur diese un/checked. Im Treeview ist es natürlich sinnvoll dann auch alle untergeordneten Item zu un/checken.
Es gibt jedoch keine Möglichkeit abzufragen, ob auf die Checkbox geklickt wurde, weil das Event CLICK dem Event CHECK vorausgeht. Über die HitItem Funktion kann ich das Item welches geklickt wurde, ermitteln. Wenn ich die Funktion zweimal aufrufe mit unterschiedlichen Parametern, weiß ich auch, ob ich nicht auf den Text geklickt habe.
Aber ich kann dann trotzdem nicht unterscheiden, ob ich die Checkbox oder (wenn vorhanden) die Node geklickt habe. Da ich die normale Verarbeitung der Messages im TV unterbinden muß, kann ich zwar mein un/checken ausführen, aber das passiert auch beim Klick auf Node und die Funktion des Node geht verloren.
Belasse ich die Standardverarbeitung der Message, funktioniert Node (wird auch gleich als Klick auf die Checkbox gewertet) aber kein Klick auf die Checkbox selbst.
Hier mal als Bsp., gebt bei $sPathRoot einen Pfad ein, der zum Lesen einer Ordnerstruktur verwendet werden soll.
#include <File.au3>
#include <FileConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiTreeView.au3>
#include <StructureConstants.au3>
#include <TreeViewConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
; TEST-SEITE
; !!! Bitte einen existierenden Pfad zum Erstellen des Treeview angeben
; !!! NICHT C:\ nehmen - sonst crasht es wegen Überschreiten der Rekursionstiefe ;)
Global $sPathRoot = 'C:\Code_Python'
Global $aAllItem[1][4] = [[0]]
Global $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
Global $iStyleEx = BitOR($WS_EX_COMPOSITED, $WS_EX_CLIENTEDGE)
$hGui = GUICreate('Test TV - Folderstruct')
Global $cTreeview = GUICtrlCreateTreeView(20, 20, 300, 320, $iStyle, $iStyleEx)
Global $hTreeview = GUICtrlGetHandle($cTreeview)
_GUICtrlTreeView_SetBkColor($hTreeview, 0x003463)
_GUICtrlTreeView_SetTextColor($hTreeview, 0xE0E0E0)
_GUICtrlTreeView_SetLineColor($hTreeview, 0xBACEFF)
GUISetState()
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
_GUICtrlTreeView_BeginUpdate($hTreeview)
_FillTreeviewFromFolder($hTreeview, 0, $sPathRoot, $sPathRoot, True)
_GUICtrlTreeView_EndUpdate($hTreeview)
_GUICtrlTreeView_Expand($hTreeview)
Do
Until GUIGetMsg() = -3
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg, $wParam
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview = $hTreeview, $fCheck, $hParent
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch $hWndFrom
Case $hWndTreeview
Switch $iCode
Case $NM_CLICK
Local $iItem = _GUICtrlTreeView_GetItemClicked($hGui, $hWndTreeview)
If @error Then Return $GUI_RUNDEFMSG
ConsoleWrite("!> CLICKED: " & _GUICtrlTreeView_GetText($hWndTreeview, $iItem) & @LF)
$fCheck = Not _GUICtrlTreeView_GetChecked($hWndTreeview, $iItem)
_CheckItemRec($hWndTreeview, $iItem, $fCheck)
_GUICtrlTreeView_SetChecked($hWndTreeview, $iItem, $fCheck)
;~ ; wenn TRUE - sicher stellen, dass Parents auch gecheckt werden
If $fCheck Then
$hParent = _GUICtrlTreeView_GetParentHandle($hWndTreeview, $iItem)
If $hParent Then
Do
_GUICtrlTreeView_SetChecked($hWndTreeview, $hParent, True)
$hParent = _GUICtrlTreeView_GetParentHandle($hWndTreeview, $hParent)
Until $hParent = 0
EndIf
EndIf
ConsoleWrite('>> Un/Check ORDNER: ' & _GUICtrlTreeView_GetText($hWndTreeview, $iItem) & @CRLF)
Return 1 ; nonzero to not allow the default processing
;~ Return $GUI_RUNDEFMSG
Case $TVN_BEGINDRAGA, $TVN_BEGINDRAGW, $TVN_BEGINLABELEDITA, $TVN_BEGINLABELEDITW, $TVN_BEGINRDRAGA, $TVN_BEGINRDRAGW, _
$TVN_DELETEITEMA, $TVN_DELETEITEMW, $TVN_ENDLABELEDITA, $TVN_ENDLABELEDITW
Return 1
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY
; Treeview befüllen mit der Ordnerstruktur eines übergebenen Pfades
Func _FillTreeviewFromFolder($hwnd, $hParent, $sPathParent, $sPathChild, $fCheckall=False)
Local $aDir = _GetFolder($sPathChild), $hItem
If $aDir[0] > 0 Then
For $i = 1 To $aDir[0]
$aAllItem[0][0] += 1
ReDim $aAllItem[$aAllItem[0][0]+1][4]
$hItem = _GUICtrlTreeView_AddChild($hwnd, $hParent, _StripPath($aDir[$i]))
If $fCheckall Then _GUICtrlTreeView_SetChecked($hwnd, $hItem)
$aAllItem[$aAllItem[0][0]][0] = $hParent
$aAllItem[$aAllItem[0][0]][1] = $hItem
$aAllItem[$aAllItem[0][0]][2] = $sPathParent
$aAllItem[$aAllItem[0][0]][3] = $aDir[$i]
_FillTreeviewFromFolder($hwnd, $hItem, $aDir[$i], $aDir[$i], $fCheckall)
Next
EndIf
EndFunc
; Rückgabe Array mit allen Pfaden der Ordner eines Verzeichnisses (nicht rekursiv)
Func _GetFolder($sPath)
Local $aFolder = _FileListToArrayRec($sPath, "*", $FLTAR_FOLDERS, $FLTAR_NORECUR, $FLTAR_SORT, $FLTAR_FULLPATH)
If @error Then Local $aFolder[1] = [0]
Return $aFolder
EndFunc
; Rückgabe Ordnername oder Pfad ohne Ordnername
Func _StripPath($sFullPath, $retPath=0)
Local $i = StringInStr($sFullPath, '\', 0, -1)
If $retPath = 1 Then Return StringLeft($sFullPath, $i-1)
Return StringTrimLeft($sFullPath, $i)
EndFunc
; Check eines Item und aller seiner Subitem, rekursiv
Func _CheckItemRec($hwnd, $hItem, $fCheck=True)
Local Static $fNext = False
; Item selbst un/checken
If $fNext Then
_GUICtrlTreeView_SetChecked($hwnd, $hItem, $fCheck)
Else
$fNext = True
EndIf
; alle Childs und deren Childs ermitteln
Local $aChild = _GuiCtrlTreeView_GetChildArray($hwnd, $hItem)
If $aChild[0] > 0 Then
For $i = 1 To $aChild[0]
_CheckItemRec($hwnd, $aChild[$i], $fCheck)
Next
EndIf
EndFunc
; Rückgabe Array mit allen Child-Item(Handle) eines Item
Func _GuiCtrlTreeView_GetChildArray($hwnd, $hParent)
Local $iChild = _GUICtrlTreeView_GetChildCount($hwnd, $hParent)
Local $aChild[1] = [0], $hItem
If $iChild = -1 Then Return $aChild
$hItem = _GUICtrlTreeView_GetFirstChild($hwnd, $hParent)
_ArrayAdd($aChild, $hItem)
$aChild[0] += 1
$hItem = _GUICtrlTreeView_GetNextSibling($hwnd, $hItem)
While $hItem <> 0
_ArrayAdd($aChild, $hItem)
$aChild[0] += 1
$hItem = _GUICtrlTreeView_GetNextSibling($hwnd, $hItem)
WEnd
Return $aChild
EndFunc
; Rückgabe Handle des geklickten Item (-1 wenn unter letztem Item geklickt)
Func _GUICtrlTreeView_GetItemClicked($hGui, $hTreeview, $bTextOnly=False)
Local $tPOINT = _WinAPI_GetMousePos(True, $hGui)
Local $iX = DllStructGetData($tPOINT, "X")
Local $iY = DllStructGetData($tPOINT, "Y")
Local $aPos = ControlGetPos($hGui, "", $hTreeview)
Local $hItem = _GUICtrlTreeView_HitTestItem($hTreeview, $iX - $aPos[0], $iY - $aPos[1])
; Item-Rectangle abfragen, $hItem gibt 0 zurück bei Klick unter letztes Item. Wird von anderen Funkt. als Handle interpretiert
; aber DisplayRect gibt korrekterweise einen Fehler aus
_GUICtrlTreeView_DisplayRect($hTreeview, $hItem, $bTextOnly)
If Not @error Then
Return $hItem
Else
Return SetError(1, 0, -1)
EndIf
EndFunc
Alles anzeigen
Falls ihr einen Workaround habt - nehme ich gern entgegen.
Edit:
Habe gerade gesehen, dass über Hittest noch brauchbare Infos kommen. Werde ich gleich mal umsetzen. Sieht vielversprechend aus.