找回密码
 加入
搜索
查看: 1803|回复: 5

[交流] 实现TreeListView,TreeView+ListView

[复制链接]
发表于 2021-3-28 22:06:02 | 显示全部楼层 |阅读模式
这些代码是从外网抄来的。把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[1][1]
;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[0])
        $anTLV_SubItem2 = _GUICtrlTreeListView_AddItem($anTLV, "My File " & $i & ".txt|File|" &  Round(Random(1, 5), 1) & " kb", $anTLV_Item[0])

        _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[2], $hTV, $aTVPos, $aLVPos, $iColsCount, $iLVWidth, $iColWidth

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

        $hTV = GUICtrlGetHandle($anTLV[0])

        __GUICtrlTreeListView_SetFont($anTLV[1], _SendMessage($hTV, $WM_GETFONT))
        ;_GUICtrlListView_SetExtendedListViewStyle($anTLV[1], $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[0])
        $aLVPos = ControlGetPos($hWnd, "", $anTLV[1])

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

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

                _GUICtrlListView_SetColumnWidth($anTLV[1], 0, $aTVPos[2])
        EndIf

        GUIRegisterMsg($WM_NOTIFY, "__GUICtrlTreeListView_WM_NOTIFY")

        Return $anTLV
EndFunc

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

        $i_TLV_CHANGING = True

        If $nTVCtrl = -1 Then
                $nTVCtrl = $anTLV[0]
        EndIf

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

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

        $a_TLV_DATA[$a_TLV_DATA[0][0]][0] = $anTLV[0]                ;TreeView ID
        $a_TLV_DATA[$a_TLV_DATA[0][0]][1] = $anTLV[1]                ;ListView ID
        $a_TLV_DATA[$a_TLV_DATA[0][0]][2] = $anTLV_Item[0]         ;Added TV Item ID
        $a_TLV_DATA[$a_TLV_DATA[0][0]][3] = $anTLV_Item[1]         ;Added LV Item ID
        $a_TLV_DATA[$a_TLV_DATA[0][0]][4] = $sItemText                ;LV Item Text (including SubItems delimited with |)
        $a_TLV_DATA[$a_TLV_DATA[0][0]][5] = $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[0], $nTVCtrl[0], $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[0][0]
                $hTreeView = GUICtrlGetHandle($a_TLV_DATA[$i][0])
                $hListView = GUICtrlGetHandle($a_TLV_DATA[$i][1])
                $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][0], 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][0], $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][0])
                                                Local $iTVItemIndx = 0

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

                                                        $iTVItemIndx += 1
                                                WEnd

                                                $i_TLV_CHANGING = True

                                                ;ControlListView($hWnd, '', $a_TLV_DATA[$i][0], '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[0]
                                                        Local $iTVItemID = _GUICtrlTreeView_GetItemParam($hTreeView, $hTVItem) ;$aLVItem[0]

                                                        For $j = 1 To $a_TLV_DATA[0][0]
                                                                If $iTVItemID = $a_TLV_DATA[$j][2] 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][3])
                                                                                        $a_TLV_DATA[$x][3] = 0
                                                                                Next
                                                                        Else
                                                                                Local $iLVSelItem = _GUICtrlListView_GetSelectedIndices($hListView)

                                                                                _GUICtrlListView_DeleteAllItems($hListView)

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

                                                                                        ;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][0], $hParent) Then
                                                                                                ContinueLoop
                                                                                        EndIf

                                                                                        ;Otherwise we create the item (it's visible) and reset the LV Item ID
                                                                                        $a_TLV_DATA[$x][3] = GUICtrlCreateListViewItem($a_TLV_DATA[$x][4], $a_TLV_DATA[$i][1])
                                                                                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[0] 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[0] 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[0] <> 1)
EndFunc


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2021-3-29 07:15:30 | 显示全部楼层
下载看看,谢谢,。。
之前也在愁这个,后期就放弃弄这个了
发表于 2021-3-29 13:12:17 | 显示全部楼层
本帖最后由 afan 于 2021-3-29 13:30 编辑

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


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2021-3-30 10:32:22 | 显示全部楼层
谢谢楼主慷慨分享。
 楼主| 发表于 2021-3-31 17:55:26 来自手机 | 显示全部楼层
afan 发表于 2021-3-29 13:12
这个可能费力不讨好……除了可折叠,光 ListView 也可以做得更好。当然 ListView 使点劲肯定也能达到折叠效 ...

主要是有些场景用这种tree+listview的方式呈现的数据更整洁。 单纯一个listview表现不出层级关系来
发表于 2021-4-6 20:46:28 | 显示全部楼层
afan 发表于 2021-3-29 13:12
这个可能费力不讨好……除了可折叠,光 ListView 也可以做得更好。当然 ListView 使点劲肯定也能达到折叠效 ...

图标都不一样,就很高大上 .
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-4-25 22:59 , Processed in 0.075880 second(s), 20 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表