MattyD Posted Wednesday at 07:10 AM Posted Wednesday at 07:10 AM (edited) Hi All, This one is a supporting thread for Ticket #4080. Feel free to add thoughts/comments... New functions: _GUICtrlTreeView_GetExtendedStyle _GUICtrlTreeView_SetExtendedStyle _GUICtrlTreeView_SetCheck (not sure how to name this?) the existing _GUICtrlTreeView_SetChecked takes a booloean, and sets the state to either 0x1000 or 0x2000. New Constants: Messages: $TVM_SETEXTENDEDSTYLE $TVM_GETEXTENDEDSTYLE EXStyles Checkboxes $TVS_EX_PARTIALCHECKBOXES $TVS_EX_EXCLUSIONCHECKBOXES $TVS_EX_DIMMEDCHECKBOXES $TVS_EX_DOUBLEBUFFER $TVS_EX_NOINDENTSTATE $TVS_EX_AUTOHSCROLL $TVS_EX_FADEINOUTEXPANDOS Untested as of yet: (at least by me!) $TVS_EX_DRAWIMAGEASYNC $TVS_EX_RICHTOOLTIP Excluded Styles (to not support.) TVS_EX_NOSINGLECOLLAPSE (MS says "apps shouldn't use") TVS_EX_MULTISELECT (MS says "do not use") Examples: Spoiler Example 1: Extended checkboxes and _GUICtrlTreeView_GetExtendedStyle expandcollapse popup#include <GuiTreeView.au3> #include <GuiConstants.au3> Global Const $TVM_SETEXTENDEDSTYLE = 0x112C Global Const $TVM_GETEXTENDEDSTYLE = 0x112D ;Checkbox Options - Treeview must NOT have TVS_CHECKBOXES for this. Global Const $TVS_EX_PARTIALCHECKBOXES = 0x0080 Global Const $TVS_EX_EXCLUSIONCHECKBOXES = 0x0100 Global Const $TVS_EX_DIMMEDCHECKBOXES = 0x0200 ;a node is selected because its parent is selected. Looks like an ordinary tick on win11. ;By default clicking items will cycle through the states. ;Programatically setting states on click isn't really straight forward - you have to handle NM_CLICK and TVN_KEYDOWN for spacebar. ;if its useful for the UDF, I've also written some code for 3-state TVIs that cascades checks down the tree, and updates the parents ... Example() Func Example() Local $hGUI = GUICreate("Example", 300, 200) Local $hTreeView = _GUICtrlTreeView_Create($hGUI, 4, 4, 292, 192) _GUICtrlTreeView_SetExtendedStyle($hTreeView, BitOR($TVS_EX_PARTIALCHECKBOXES, $TVS_EX_DIMMEDCHECKBOXES, $TVS_EX_EXCLUSIONCHECKBOXES)) Local $iExStyle = _GUICtrlTreeView_GetExtendedStyle($hTreeView) ConsoleWrite("Extended Style = 0x" & Hex($iExStyle, 4) & @CRLF) ConsoleWrite("Support Partial Boxes = " & (BitAND($iExStyle, $TVS_EX_PARTIALCHECKBOXES) = $TVS_EX_PARTIALCHECKBOXES) & @CRLF) ConsoleWrite("Support Exclusion Boxes = " & (BitAND($iExStyle, $TVS_EX_EXCLUSIONCHECKBOXES) = $TVS_EX_EXCLUSIONCHECKBOXES) & @CRLF) ConsoleWrite("Support Dimmed Boxes = " & (BitAND($iExStyle, $TVS_EX_DIMMEDCHECKBOXES) = $TVS_EX_DIMMEDCHECKBOXES) & @CRLF) Local $hItem, $asCheckMarks[] = ["None", "Unchecked", "Checked", "Partial", "Dimmed", "Exclude"] For $i = 0 To 5 $hItem = _GUICtrlTreeView_AddChild($hTreeView, $TVI_ROOT, _ StringFormat("Index:%d State:0x%04X %s", $i, BitShift($i, -12), $asCheckMarks[$i])) _GUICtrlTreeView_SetCheck($hTreeView, $hItem, $i) Next GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc Func _GUICtrlTreeView_SetExtendedStyle($hTreeView, $iExStyle) Local $iResult = _SendMessage($hTreeView, $TVM_SETEXTENDEDSTYLE, 0x7FFD, $iExStyle) ;0x7FFD = bits to set. $TVS_EX_MULTISELECT (2) is unset as it's documented as "Do not Use." Return SetError(@error, @extended, $iResult) EndFunc Func _GUICtrlTreeView_GetExtendedStyle($hTreeView) Local $iResult = _SendMessage($hTreeView, $TVM_GETEXTENDEDSTYLE) Return SetError(@error, @extended, $iResult) EndFunc Func _GUICtrlTreeView_SetCheck($hWnd, $hItem, $iIndex) If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem) If ($iIndex > 15) Or ($iIndex < 0) Then Return SetError(1, 0, False) Local $tItem = $__g_tTVItemEx DllStructSetData($tItem, "Mask", $TVIF_STATE) DllStructSetData($tItem, "hItem", $hItem) DllStructSetData($tItem, "State", BitShift($iIndex, -12)) ;bitshift = INDEXTOSTATEIMAGEMASK macro. ;(https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-indextostateimagemask) DllStructSetData($tItem, "StateMask", $TVIS_STATEIMAGEMASK) Return __GUICtrlTreeView_SetItem($hWnd, $tItem) EndFunc Example 2: TVS_EX_AUTOHSCROLL expandcollapse popup#include <GuiTreeView.au3> #include <GuiConstants.au3> #include <ScrollbarConstants.au3> Global Const $TVM_SETEXTENDEDSTYLE = 0x112C Global Const $TVS_EX_AUTOHSCROLL = 0x0020 Example() Func Example() Local $hGUI = GUICreate("Example", 300, 400) GUICtrlCreateLabel("With TVS_EX_AUTOHSCROLL", 4, 4, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView = _GUICtrlTreeView_Create($hGUI, 4, 26, 292, 172) GUICtrlCreateLabel("Without TVS_EX_AUTOHSCROLL", 4, 204, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView2 = _GUICtrlTreeView_Create($hGUI, 4, 226, 292, 172) _GUICtrlTreeView_SetExtendedStyle($hTreeView, $TVS_EX_AUTOHSCROLL) For $i = 0 To 5 _GUICtrlTreeView_AddChild($hTreeView, $TVI_ROOT, "Some very long text is here to demonstrate auto horizontal scrolling") _GUICtrlTreeView_AddChild($hTreeView2, $TVI_ROOT, "Some very long text is here to demonstrate auto horizontal scrolling") Next ;Scroll right as starting point for demo. ;TreeView with $TVS_EX_AUTOHSCROLL will scroll back to the left with mouse hover. _SendMessage($hTreeView, $WM_HSCROLL, $SB_PAGERIGHT, 0) _SendMessage($hTreeView2, $WM_HSCROLL, $SB_PAGERIGHT, 0) GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc Func _GUICtrlTreeView_SetExtendedStyle($hTreeView, $iExStyle) Local $iResult = _SendMessage($hTreeView, $TVM_SETEXTENDEDSTYLE, 0x07FD, $iExStyle) Return SetError(@error, @extended, $iResult) EndFunc Example 3: TVS_EX_FADEINOUTEXPANDOS and TVS_EX_DOUBLEBUFFER expandcollapse popup#include <GuiTreeView.au3> #include <GuiConstants.au3> Global Const $TVM_SETEXTENDEDSTYLE = 0x112C Global Const $TVS_EX_DOUBLEBUFFER = 0x0004 Global Const $TVS_EX_FADEINOUTEXPANDOS = 0x0040 Example() Func Example() ;click on items from treeview into another. Local $hGUI = GUICreate("Example", 300, 454) GUICtrlCreateLabel("With FADEINOUTEXPANDOS and DOUBLEBUFFER", 4, 4, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView = _GUICtrlTreeView_Create($hGUI, 4, 26, 292, 122) _GUICtrlTreeView_SetExtendedStyle($hTreeView, BitOR($TVS_EX_FADEINOUTEXPANDOS, $TVS_EX_DOUBLEBUFFER)) GUICtrlCreateLabel("Without Double Buffer", 4, 154, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView2 = _GUICtrlTreeView_Create($hGUI, 4, 176, 292, 122) ;Flickers when you click away. _GUICtrlTreeView_SetExtendedStyle($hTreeView2, $TVS_EX_FADEINOUTEXPANDOS) GUICtrlCreateLabel("Without Expanded styles", 4, 304, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView3 = _GUICtrlTreeView_Create($hGUI, 4, 326, 292, 122) _AddItems($hTreeView) _AddItems($hTreeView2) _AddItems($hTreeView3) GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc Func _AddItems($hTreeView) Local $hItem = $TVI_ROOT For $i = 0 To 5 $hItem = _GUICtrlTreeView_AddChild($hTreeView, $hItem, "Tree View Item " & $i) Next _GUICtrlTreeView_Expand($hTreeView) EndFunc Func _GUICtrlTreeView_SetExtendedStyle($hTreeView, $iExStyle) Local $iResult = _SendMessage($hTreeView, $TVM_SETEXTENDEDSTYLE, 0x07FD, $iExStyle) Return SetError(@error, @extended, $iResult) EndFunc Example 4: TVS_EX_NOINDENTSTATE expandcollapse popup#include <GuiTreeView.au3> #include <GuiConstants.au3> #include <ScrollBarConstants.au3> Global Const $TVM_SETEXTENDEDSTYLE = 0x112C Global Const $TVS_EX_NOINDENTSTATE = 0x0008 Example() Func Example() Local $hGUI = GUICreate("Example", 300, 400) GUICtrlCreateLabel("With TVS_EX_NOINDENTSTATE", 4, 4, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView = _GUICtrlTreeView_Create($hGUI, 4, 26, 292, 172, BitOR($TVS_DEFAULT, $TVS_CHECKBOXES)) _GUICtrlTreeView_SetExtendedStyle($hTreeView, $TVS_EX_NOINDENTSTATE) GUICtrlCreateLabel("Without TVS_EX_NOINDENTSTATE", 4, 204, 292, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Local $hTreeView2 = _GUICtrlTreeView_Create($hGUI, 4, 226, 292, 172, BitOR($TVS_DEFAULT, $TVS_CHECKBOXES)) _AddItems($hTreeView) _AddItems($hTreeView2) GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc Func _AddItems($hTreeView) Local $hItem = $TVI_ROOT For $i = 0 To 5 $hItem = _GUICtrlTreeView_AddChild($hTreeView, $hItem, "Tree View Item " & $i) Next _GUICtrlTreeView_Expand($hTreeView) EndFunc Func _GUICtrlTreeView_SetExtendedStyle($hTreeView, $iExStyle) Local $iResult = _SendMessage($hTreeView, $TVM_SETEXTENDEDSTYLE, 0x07FD, $iExStyle) Return SetError(@error, @extended, $iResult) EndFunc Edited Wednesday at 07:44 AM by MattyD techicalities ioa747 and pixelsearch 2
jpm Posted Wednesday at 08:48 AM Posted Wednesday at 08:48 AM Many Thanks I was waiting example so now I can commit MattyD 1
WildByDesign Posted Wednesday at 09:51 AM Posted Wednesday at 09:51 AM Some truly excellent work, Matty. I remember wanting to use TVS_EX_DOUBLEBUFFER somewhat recently but couldn't understand why it wasn't available in AutoIt. The addition of the various checkbox states is also incredibly helpful. Thanks for bringing all of these TreeView extended styles to AutoIt. MattyD 1
MattyD Posted Wednesday at 02:04 PM Author Posted Wednesday at 02:04 PM no worries, FWIW here's that first attempt at cascading boxes, which makes the indeterminate box actually useful! The "box clicked by mouse" logic was borrowed from here... I probably should've attempted to suppress the auto-state change rather than fixing things after the fact- but hey. expandcollapse popup#include <GuiTreeView.au3> #include <GuiConstants.au3> #include <WinAPIvkeysConstants.au3> #include <WinAPISysWin.au3> #include <ScrollbarConstants.au3> Global Const $TVM_SETEXTENDEDSTYLE = 0x112C Global Const $TVM_GETEXTENDEDSTYLE = 0x112D ;~ Global Const $TVN_ITEMCHANGING = ($TVN_FIRST - 17) Global Const $TVS_EX_PARTIALCHECKBOXES = 0x0080 Global Const $tagTVKEYDOWN = "struct;" & $tagNMHDR & ";word wVKey;uint flags;endstruct" Global Const $UM_CHECKSTATECHANGE = $WM_USER + 100 ;user-defined message Example() Func Example() GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUIRegisterMsg($UM_CHECKSTATECHANGE, "UM_CHECKSTATECHANGE") Local $hGUI = GUICreate("Example", 300, 400) Local $hTreeView = _GUICtrlTreeView_Create($hGUI, 4, 4, 292, 392) _GUICtrlTreeView_SetExtendedStyle($hTreeView, $TVS_EX_PARTIALCHECKBOXES) Local $ahItems[20] = [$TVI_ROOT] For $i = 0 To UBound($ahItems) - 1 $ahItems[$i] = _GUICtrlTreeView_AddChild($hTreeView, $ahItems[Floor($i/3)], "item " & $i) Next _GUICtrlTreeView_Expand($hTreeView) GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) GUIRegisterMsg($WM_NOTIFY, "") GUIRegisterMsg($UM_CHECKSTATECHANGE, "") EndFunc Func _GUICtrlTreeView_GetExtendedStyle($hTreeView) Local $iResult = _SendMessage($hTreeView, $TVM_GETEXTENDEDSTYLE) Return SetError(@error, @extended, $iResult) EndFunc Func _GUICtrlTreeView_SetExtendedStyle($hTreeView, $iExStyle) Local $iResult = _SendMessage($hTreeView, $TVM_SETEXTENDEDSTYLE, 0x7FFD, $iExStyle) Return SetError(@error, @extended, $iResult) EndFunc Func _GUICtrlTreeView_SetCheck($hWnd, $hItem, $iIndex) If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem) If ($iIndex > 15) Or ($iIndex < 0) Then Return SetError(1, 0, False) Local $tItem = $__g_tTVItemEx DllStructSetData($tItem, "Mask", $TVIF_STATE) DllStructSetData($tItem, "hItem", $hItem) DllStructSetData($tItem, "State", BitShift($iIndex, -12)) DllStructSetData($tItem, "StateMask", $TVIS_STATEIMAGEMASK) Return __GUICtrlTreeView_SetItem($hWnd, $tItem) EndFunc Func _GUICtrlTreeView_GetCheck($hWnd, $hItem) If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem) Local $tItem = $__g_tTVItemEx DllStructSetData($tItem, "Mask", $TVIF_STATE) DllStructSetData($tItem, "hItem", $hItem) DllStructSetData($tItem, "StateMask", $TVIS_STATEIMAGEMASK) __GUICtrlTreeView_GetItem($hWnd, $tItem) Return BitShift(DllStructGetData($tItem, "State"), 12) EndFunc Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Switch _WinAPI_GetClassName($tNMHDR.hWndFrom) Case "SysTreeView32" ;Check this is a 3-state TreeView. Local $iExStyle = _GUICtrlTreeView_GetExtendedStyle($tNMHDR.hWndFrom) If BitAND(0x380, $iExStyle) = $TVS_EX_PARTIALCHECKBOXES Then Switch $tNMHDR.Code Case $NM_CLICK ;Get mouse location when msg was fired. Local $iMsgPos = _WinAPI_GetMessagePos() Local $tPoint = DllStructCreate($tagPOINT) $tPoint.X = _WinAPI_WordToShort(_WinAPI_LoWord($iMsgPos)) $tPoint.Y = _WinAPI_WordToShort(_WinAPI_HiWord($iMsgPos)) _WinAPI_ScreenToClient($tNMHDR.hWndFrom, $tPoint) ;Relative to control ;Did we click a checkbox? Local $tTVHITTESTINFO = _GUICtrlTreeView_HitTestEx($tNMHDR.hWndFrom, $tPoint.X, $tPoint.Y) If BitAND($tTVHITTESTINFO.Flags, $TVHT_ONITEMSTATEICON) Then _ _WinAPI_PostMessage($hWnd, $UM_CHECKSTATECHANGE, $tNMHDR.hWndFrom, $tTVHITTESTINFO.Item) ;At this point the checkbox hasn't changed state. We don't want to cascade now - hence the postmsg. Case $TVN_KEYDOWN Local $tVKeyDown = DllStructCreate($tagTVKEYDOWN, $lParam) If $tVKeyDown.wVKey = $VK_SPACE Then _ _WinAPI_PostMessage($hWnd, $UM_CHECKSTATECHANGE, $tNMHDR.hWndFrom, _GUICtrlTreeView_GetSelection($tNMHDR.hWndFrom)) EndSwitch EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func UM_CHECKSTATECHANGE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam _GUICtrlTreeView_BeginUpdate($wParam) Local $iTgtState = _GUICtrlTreeView_GetCheck($wParam, $lParam) Switch $iTgtState Case 1 ; Item was indeterminate but click changed to unchecked. Correct this so indeterminate -> checked. $iTgtState = 2 Case 3 ; Item was checked, but click changed to indeterminate. Correct this so check -> unchecked. $iTgtState = 1 EndSwitch _GUICtrlTreeView_SetCheck($wParam, $lParam, $iTgtState) Local $hCurrent, $hNext, $hParent ;Work up the chain... ;Get the first sibling on our checkbox's level. $hParent = _GUICtrlTreeView_GetParentHandle($wParam, $lParam) $hNext = _GUICtrlTreeView_GetFirstChild($wParam, $hParent) While $hNext ;Check all siblings on this level. ;If the states don't all match, then the parent should be indeterminate. Otherwise it should mimic its children. $hCurrent = $hNext If _GUICtrlTreeView_GetCheck($wParam, $hCurrent) <> $iTgtState Then $iTgtState = 3 $hNext = _GUICtrlTreeView_GetNextSibling($wParam, $hCurrent) ;If there is a indeterminate box on this level, then the parent will also be indeterminate. So no need to check further in that case. If Not $hNext Or $iTgtState = 3 Then ;set the parent's state. $hParent = _GUICtrlTreeView_GetParentHandle($wParam, $hCurrent) If Not $hParent Then ExitLoop $hCurrent = $hParent If _GUICtrlTreeView_GetCheck($wParam, $hCurrent) <> $iTgtState Then _ _GUICtrlTreeView_SetCheck($wParam, $hCurrent, $iTgtState) ;Get the first sibling on the parent's level. $hParent = _GUICtrlTreeView_GetParentHandle($wParam, $hCurrent) $hNext = _GUICtrlTreeView_GetFirstChild($wParam, $hParent) EndIf WEnd ;Cascade Down $iTgtState = _GUICtrlTreeView_GetCheck($wParam, $lParam) ;Get first descendant. $hNext = _GUICtrlTreeView_GetFirstChild($wParam, $lParam) While $hNext $hCurrent = $hNext _GUICtrlTreeView_SetCheck($wParam, $hCurrent, $iTgtState) ;Go down a level if possible. $hNext = _GUICtrlTreeView_GetFirstChild($wParam, $hCurrent) ;otherwise move across this level. If Not $hNext Then $hNext = _GUICtrlTreeView_GetNextSibling($wParam, $hCurrent) While Not $hNext ;done on this level and everything below, - go back to the parent (which has already been processed). $hParent = _GUICtrlTreeView_GetParentHandle($wParam, $hCurrent) If $hParent = $lParam Then ExitLoop ;Back at our original checkbox. breakout! ;Continue on the parent's level if possible. $hNext = _GUICtrlTreeView_GetNextSibling($wParam, $hParent) $hCurrent = $hParent WEnd WEnd _GUICtrlTreeView_EndUpdate($wParam) EndFunc Func _WinAPI_GetMessagePos() Local $aCall = DllCall("user32.dll", "dword", "GetMessagePos") If @error Then Return SetError(@error, @extended, $aCall) Return $aCall[0] EndFunc argumentum and ioa747 2
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now