ws7721 发表于 2021-3-28 22:06:02

实现TreeListView,TreeView+ListView

这些代码是从外网抄来的。把TreeView和ListView合在了一起。但是实际使用过程中仍存在瑕疵,如TreeView和ListView滚轮事件未能完全同步,TreeView当建到第三层的时候可能出现折叠不同步现象。另外选中项目后两个控件颜色有偏差,看起来就像是硬凑在一起的控件。 本人新手一枚,能力有限。把代码放上来望大神们进行完善。目前效果如图
代码如下,另附件同代码:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <FontConstants.au3>
#Include <ScrollBarConstants.au3>
#Include <GUIScrollBars.au3>
#include <GUIListView.au3>
#include <GUITreeView.au3>
#include <WinAPI.au3>

Global $i_TLV_CHANGING = False
Global $i_TLV_SEL_CHANGED = False
Global $a_TLV_DATA
;Global $h_TLV_FONT = _WinAPI_CreateFont(14, 6, 0, 0, 0, False, False, False, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, 0, 'Arial')

$hGUI = GUICreate("TreeListView Test", 700, 500)

$anTLV = _GUICtrlTreeListView_Create($hGUI, 10, 10, 680, 480)

For $i = 1 To 5
        $anTLV_Item = _GUICtrlTreeListView_AddItem($anTLV, "My Folder " & $i & "|Folder|" & Round(Random(1, 5), 1) & " mb")
        $anTLV_SubItem1 = _GUICtrlTreeListView_AddItem($anTLV, "My Script " & $i & ".au3|File|" &Round(Random(1, 5), 1) & " kb", $anTLV_Item)
        $anTLV_SubItem2 = _GUICtrlTreeListView_AddItem($anTLV, "My File " & $i & ".txt|File|" &Round(Random(1, 5), 1) & " kb", $anTLV_Item)

        _GUICtrlTreeListView_ExpandItem($anTLV, $anTLV_Item, True)
Next

GUISetState(@SW_SHOW, $hGUI)

While 1
        $nMsg = GUIGetMsg()

        Switch $nMsg
                Case $GUI_EVENT_CLOSE
                        Exit
        EndSwitch
WEnd

Func _GUICtrlTreeListView_Create($hWnd, $iLeft, $iTop, $iWidth, $iHeight)
        Local $anTLV, $hTV, $aTVPos, $aLVPos, $iColsCount, $iLVWidth, $iColWidth

        $anTLV = GUICtrlCreateTreeView($iLeft + 5, $iTop + 25, ($iWidth / 2) + 10, $iHeight - 35, BitOr($GUI_SS_DEFAULT_TREEVIEW, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_NOSCROLL, $TVS_NONEVENHEIGHT))
        $anTLV = GUICtrlCreateListView("Name|Type|Size", $iLeft, $iTop, $iWidth, $iHeight, BitOr($LVS_SHOWSELALWAYS, $LVS_SINGLESEL, $WS_CLIPSIBLINGS, $LVS_NOSORTHEADER))

        $hTV = GUICtrlGetHandle($anTLV)

        __GUICtrlTreeListView_SetFont($anTLV, _SendMessage($hTV, $WM_GETFONT))
        ;_GUICtrlListView_SetExtendedListViewStyle($anTLV, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
        _GUICtrlTreeView_SetHeight($hTV, 21)
        _GUIScrollBars_EnableScrollBar($hTV, $SB_BOTH, $ESB_DISABLE_BOTH)
        _GUIScrollBars_ShowScrollBar($hTV, $SB_VERT, False)

        $aTVPos = ControlGetPos($hWnd, "", $anTLV)
        $aLVPos = ControlGetPos($hWnd, "", $anTLV)

        If UBound($aTVPos) > 2 And UBound($aLVPos) > 2 Then
                $iColsCount = _GUICtrlListView_GetColumnCount($anTLV)
                $iLVWidth = $aLVPos - ($aTVPos + 10) - 15
                $iColWidth = Floor($iLVWidth / ($iColsCount - 1))

                For $i = 1 To $iColsCount - 1
                        _GUICtrlListView_SetColumnWidth($anTLV, $i, $iColWidth)
                Next

                _GUICtrlListView_SetColumnWidth($anTLV, 0, $aTVPos)
        EndIf

        GUIRegisterMsg($WM_NOTIFY, "__GUICtrlTreeListView_WM_NOTIFY")

        Return $anTLV
EndFunc

Func _GUICtrlTreeListView_AddItem($anTLV, $sItemText, $nTVCtrl = -1)
        Local $anTLV_Item, $iItem, $aTVPos

        $i_TLV_CHANGING = True

        If $nTVCtrl = -1 Then
                $nTVCtrl = $anTLV
        EndIf

        $anTLV_Item = GUICtrlCreateTreeViewItem(StringRegExpReplace($sItemText, '^([^|]*)\|.*', '\1'), $nTVCtrl)
        $anTLV_Item = GUICtrlCreateListViewItem(StringRegExpReplace($sItemText, '^[^|]*', ''), $anTLV)

        $a_TLV_DATA += 1
        ReDim $a_TLV_DATA[$a_TLV_DATA + 1]

        $a_TLV_DATA[$a_TLV_DATA] = $anTLV                ;TreeView ID
        $a_TLV_DATA[$a_TLV_DATA] = $anTLV                ;ListView ID
        $a_TLV_DATA[$a_TLV_DATA] = $anTLV_Item         ;Added TV Item ID
        $a_TLV_DATA[$a_TLV_DATA] = $anTLV_Item         ;Added LV Item ID
        $a_TLV_DATA[$a_TLV_DATA] = $sItemText                ;LV Item Text (including SubItems delimited with |)
        $a_TLV_DATA[$a_TLV_DATA] = $nTVCtrl                ;TV Item Parent ID

        $i_TLV_CHANGING = False

        Return $anTLV_Item
EndFunc

Func _GUICtrlTreeListView_ExpandItem($anTLV, $nTVCtrl, $bExpand)
        $i_TLV_CHANGING = True

        _GUICtrlTreeView_Expand($anTLV, $nTVCtrl, $bExpand)

        $i_TLV_CHANGING = False
EndFunc

Func __GUICtrlTreeListView_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
        Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hTreeView, $hListView, $hLVHeader
        Global $iLastScrollPos

        If $i_TLV_CHANGING Then
                Return $GUI_RUNDEFMSG
        EndIf

        $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
        $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
        $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
        $iCode = DllStructGetData($tNMHDR, "Code")

        For $i = 1 To $a_TLV_DATA
                $hTreeView = GUICtrlGetHandle($a_TLV_DATA[$i])
                $hListView = GUICtrlGetHandle($a_TLV_DATA[$i])
                $hLVHeader = _GUICtrlListView_GetHeader($hListView)

                Switch $hWndFrom
                        Case $hLVHeader
                                Switch $iCode
                                        Case $HDN_ITEMCHANGING, $HDN_ITEMCHANGINGW
                                                Return 1
                                EndSwitch

                                ExitLoop
                        Case $hListView
                                Switch $iCode
                                        Case $LVN_ITEMCHANGING, $LVN_BEGINDRAG, $LVN_MARQUEEBEGIN
                                                Return 1
                                        Case $LVN_BEGINSCROLL
                                                $tSCROLLINFO = DllStructCreate($tagSCROLLINFO)
                                                DllStructSetData($tSCROLLINFO, "cbSize", DllStructGetSize($tSCROLLINFO))
                                                DllStructSetData($tSCROLLINFO, "fMask", $_SCROLLBARCONSTANTS_SIF_ALL)   ;如果在这行报错就改成 $SIF_ALL 试试

                                                _GUIScrollBars_GetScrollInfo($hListView, $SB_VERT, $tSCROLLINFO)

                                                $nPage = DllStructGetData($tSCROLLINFO, "nPage")
                                                $nPos = DllStructGetData($tSCROLLINFO, "nPos")
                                                $nMin = DllStructGetData($tSCROLLINFO, "nMin")
                                                $nMax = DllStructGetData($tSCROLLINFO, "nMax")
                                                $nTrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

                                                GUICtrlSetStyle($a_TLV_DATA[$i], BitOr($GUI_SS_DEFAULT_TREEVIEW, $TVS_HASLINES, $TVS_LINESATROOT))

                                                _GUIScrollBars_SetScrollInfo($hTreeView, $SB_VERT, $tSCROLLINFO)

                                                For $j = 1 To $nPos
                                                        GUICtrlSendMsg($a_TLV_DATA[$i], $WM_VSCROLL, $SB_LINEDOWN, 0)
                                                Next

                                                _GUIScrollBars_ShowScrollBar($hTreeView, $SB_BOTH, False)
                                        Case $LVN_ENDSCROLL
                                                _GUIScrollBars_ShowScrollBar($hTreeView, $SB_BOTH, False)
                                EndSwitch

                                ExitLoop
                        Case $hTreeView
                                Switch $iCode
                                        Case $TVN_SELCHANGEDA, $TVN_SELCHANGEDW
                                                Local $hTVItem = _GUICtrlTreeView_GetSelection($a_TLV_DATA[$i])
                                                Local $iTVItemIndx = 0

                                                While 1
                                                        $hTVItem = _GUICtrlTreeView_GetPrevVisible($a_TLV_DATA[$i], $hTVItem)
                                                        If $hTVItem = 0 Then ExitLoop

                                                        $iTVItemIndx += 1
                                                WEnd

                                                $i_TLV_CHANGING = True

                                                ;ControlListView($hWnd, '', $a_TLV_DATA[$i], 'SelectClear')
                                                _GUICtrlListView_SetItemSelected($hListView, $iTVItemIndx)

                                                $i_TLV_CHANGING = False
                                        Case $TVN_ITEMEXPANDINGA, $TVN_ITEMEXPANDINGW
                                                $i_TLV_CHANGING = True

                                                Local $tPOINT = DllStructCreate("int X;int Y")

                                                DllStructSetData($tPOINT, "X", MouseGetPos(0))
                                                DllStructSetData($tPOINT, "Y", MouseGetPos(1))

                                                _WinAPI_ScreenToClient($hTreeView, $tPOINT)

                                                Local $iX = DllStructGetData($tPOINT, "X")
                                                Local $iY = DllStructGetData($tPOINT, "Y")

                                                Local $hTVItem = _GUICtrlTreeView_HitTestItem($hTreeView, $iX, $iY)

                                                If $hTVItem = 0 Then
                                                        $hTVItem = _GUICtrlTreeView_GetSelection($hTreeView)
                                                EndIf

                                                If $hTVItem <> 0 Then
                                                        Local $iTVItemIndx = _GUICtrlTreeView_Index($hTreeView, $hTVItem) ;$aLVItem
                                                        Local $iTVItemID = _GUICtrlTreeView_GetItemParam($hTreeView, $hTVItem) ;$aLVItem

                                                        For $j = 1 To $a_TLV_DATA
                                                                If $iTVItemID = $a_TLV_DATA[$j] Then
                                                                        Local $iChilds = _GUICtrlTreeView_GetChildCount($hTreeView, $hTVItem)

                                                                        If _GUICtrlTreeView_GetExpanded($hTreeView, $hTVItem) Then
                                                                                For $x = $j + $iChilds To $j + 1 Step -1
                                                                                        GUICtrlDelete($a_TLV_DATA[$x])
                                                                                        $a_TLV_DATA[$x] = 0
                                                                                Next
                                                                        Else
                                                                                Local $iLVSelItem = _GUICtrlListView_GetSelectedIndices($hListView)

                                                                                _GUICtrlListView_DeleteAllItems($hListView)

                                                                                For $x = 1 To $a_TLV_DATA
                                                                                        $hParent = _GUICtrlTreeView_GetParentHandle($a_TLV_DATA[$i], $a_TLV_DATA[$x])

                                                                                        ;It's a child item, it's not hitted parent item (expanded), and the parent of this item is expanded
                                                                                        If $hParent And $hParent <> $hTVItem And Not _GUICtrlTreeView_GetExpanded($a_TLV_DATA[$i], $hParent) Then
                                                                                                ContinueLoop
                                                                                        EndIf

                                                                                        ;Otherwise we create the item (it's visible) and reset the LV Item ID
                                                                                        $a_TLV_DATA[$x] = GUICtrlCreateListViewItem($a_TLV_DATA[$x], $a_TLV_DATA[$i])
                                                                                Next

                                                                                _GUICtrlListView_SetItemSelected($hListView, Int($iLVSelItem))
                                                                                _GUICtrlTreeView_ClickItem($hTreeView, $hTVItem)
                                                                        EndIf

                                                                        ExitLoop
                                                                EndIf
                                                        Next
                                                EndIf

                                                $i_TLV_CHANGING = False
                                EndSwitch

                                ExitLoop
                EndSwitch
        Next

        Return $GUI_RUNDEFMSG
EndFunc

; =========================================================================================
; Name...........: _GUICtrlListView_SetFont
; Description ...: Set font for a list-view controls items and header text
; Syntax.........: _GUICtrlListView_SetFont($hWnd, $hFontLV, $hFontHD = 0)
; Parameters ....: $hWnd      - Handle to the control
;                  $hFontLV   - Handle to font
;                  $hFontHD   - Handle to header font (Optional)
; Return values .: Success      - True
;                  Failure      - False
; Author ........: rover
; Remarks .......: Use optional header font parameter for a different font/size of header
; =========================================================================================
Func __GUICtrlTreeListView_SetFont($hWnd, $hFontLV, $hFontHD = 0)
        ;If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName)
        If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
        Local $aReturn, $hHeader, $hDLL
        $hHeader = HWnd(_GUICtrlListView_GetHeader($hWnd)) ; get handle to header control

        If Not IsHWnd($hWnd) Or Not IsPtr($hFontLV) Or Not IsHWnd($hHeader) Then Return SetError(1, 0, False)

        _SendMessage($hWnd, $__LISTVIEWCONSTANT_WM_SETREDRAW, 0) ; disable repainting

        $hDLL = DllOpen("UxTheme.dll")
        ; turn off theme for header control to enable header autosizing
        $aReturn = DllCall($hDLL, "int", "SetWindowTheme", "hwnd", $hHeader, "wstr", "", "wstr", "")

        If @error Or $aReturn Then
                DllClose($hDLL)
                Return SetError(2, 0, False)
        EndIf

        If IsPtr($hFontHD) Then ; set font for items and if available separate font for header
                _SendMessage($hWnd, $__LISTVIEWCONSTANT_WM_SETFONT, $hFontLV, True, 0, "hwnd")
                _SendMessage($hHeader, $__LISTVIEWCONSTANT_WM_SETFONT, $hFontHD, True, 0, "hwnd")
        Else ; set same font for header and items
                ; resizing header down to a smaller font size causes listview repaint problems, so repainting is enabled
                _SendMessage($hWnd, $__LISTVIEWCONSTANT_WM_SETREDRAW, 1) ; enable repainting
                _SendMessage($hWnd, $__LISTVIEWCONSTANT_WM_SETFONT, $hFontLV, True, 0, "hwnd")
        EndIf

        ; restore control theme painting
        $aReturn = DllCall($hDLL, "int", "SetWindowTheme", "hwnd", $hHeader, "ptr", 0, "ptr", 0)

        If @error Or $aReturn Then
                DllClose($hDLL)
                Return SetError(3, 0, False)
        EndIf

        DllClose($hDLL)

        _SendMessage($hWnd, $__LISTVIEWCONSTANT_WM_SETREDRAW, 1) ; enable repainting
        _WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE)

        Return SetError(0, 0, $aReturn <> 1)
EndFunc


yuantian 发表于 2021-3-29 07:15:30

下载看看,谢谢,。。
之前也在愁这个,后期就放弃弄这个了
:face (2):

afan 发表于 2021-3-29 13:12:17

本帖最后由 afan 于 2021-3-29 13:30 编辑

这个可能费力不讨好……除了可折叠,光 ListView 也可以做得更好。当然 ListView 使点劲肯定也能达到折叠效果
比如我的 iWheel 配置界面


koko4u 发表于 2021-3-30 10:32:22

谢谢楼主慷慨分享。

ws7721 发表于 2021-3-31 17:55:26

afan 发表于 2021-3-29 13:12
这个可能费力不讨好……除了可折叠,光 ListView 也可以做得更好。当然 ListView 使点劲肯定也能达到折叠效 ...

主要是有些场景用这种tree+listview的方式呈现的数据更整洁。 单纯一个listview表现不出层级关系来

.Simba 发表于 2021-4-6 20:46:28

afan 发表于 2021-3-29 13:12
这个可能费力不讨好……除了可折叠,光 ListView 也可以做得更好。当然 ListView 使点劲肯定也能达到折叠效 ...

图标都不一样,就很高大上 .
页: [1]
查看完整版本: 实现TreeListView,TreeView+ListView