# TreeView [v1.0.44+]

## 目录

- 入门和简单示例
- 选项和样式
- 内置函数: 1) 添加/修改/删除项目; 2) 从 TreeView 中获取数据
- G-Label 通告
- 备注
- 更长的范例

## 入门和简单示例

Tree-View 通过在父项目下缩进它们的子项目来显示出项目的层级关系. 最常见的例子是资源管理器的驱动器和文件夹树.

创建 TreeView 的语法为:

Gui, Add, TreeView, Options

这里是一个创建和显示一个简单项目层次结构的有效脚本:

    Gui, Add, TreeView
    P1 := TV_Add("First parent")
    P1C1 := TV_Add("Parent 1's first child", P1)  ; Specify P1 to be this item's parent.
    P2 := TV_Add("Second parent")
    P2C1 := TV_Add("Parent 2's first child", P2)
    P2C2 := TV_Add("Parent 2's second child", P2)
    P2C2C1 := TV_Add("Child 2's first child", P2C2)

    Gui, Show  ; Show the window and its TreeView.
    return

    GuiClose:  ; Exit the script when the user closes the TreeView's GUI window.
    ExitApp

## 用于 "Gui, Add, TreeView, Options" 的样式和选项

AltSubmit: 通知脚本有比正常更多的 TreeView 事件类型. 换言之, g-label 运行的更频繁.参见 TreeView 通告 获取详情.

Background: 指定单词 Background 接着一个颜色名称 (参见 颜色图表) 或 RGB 值 (0x 前缀是可选的).例如: BackgroundSilver, BackgroundFFDD99. 如果此选项不存在, TreeView 最初默认的背景颜色由 Gui Color (或者如果没有, 则使用系统默认的背景颜色) 的最后一个参数设置. 指定 BackgroundDefault 应用系统的默认背景颜色 (通常为白色).例如, 通过 GuiControl, +BackgroundDefault, MyTreeView 可以把 TreeView 恢复为默认的颜色.

Buttons: 指定 -Buttons (负 Buttons) 以避免在每个含有子项目的项目左边显示一个加号或减号按钮.

C: 文本颜色. 指定字母 C 接着一个颜色名称 (参见 颜色图表) 或 RGB 值 (0x 前缀是可选的).例如: cRed, cFF2211, c0xFF2211, cDefault

Checked: 在每项的左边提供一个复选框. 当 添加 一项时, 在其选项中指定单词 Check 使复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中一项. 要找出 TreeView 中当前选中了哪些项目, 请调用 TV_GetNext() 或 TV_Get().

HScroll: 指定 -HScroll (负 HScroll) 来禁用控件中的水平滚动 (此外, 控件将不显示水平滚动条). 在比 Windows 2000/Me 老的操作系统中, 此选项没有效果除非系统中有 Comctl32.dll 5.8 或更高版本 (随应用程序例如 Internet Explorer 5 或更高版本一起发布).

ImageList: 这是通过它把图标添加到 TreeView 的方法. 指定单词 ImageList 接着之前调用 IL_Create() 返回的 ImageListID. 此选项仅当创建 TreeView 时才有效果. 这里是一个有效的示例:

    ImageListID := IL_Create(10)  ; Create an ImageList with initial capacity for 10 icons.
    Loop 10  ; Load the ImageList with some standard system icons.
        IL_Add(ImageListID, "shell32.dll", A_Index)  ; Omits the DLL's path so that it works on Windows 9x too.
    Gui, Add, TreeView, ImageList%ImageListID%
    TV_Add("Name of Item", 0, "Icon4")  ; Add an item to the TreeView and give it a folder icon.
    Gui Show

Lines: 指定 -Lines (负 Lines) 来避免显示连接父项目和它们的子项目的网状线. 但是, 移除这些线也阻止了顶级项目左边加号/减号按钮的显示.

ReadOnly: 指定 -ReadOnly (负 ReadOnly) 来允许编辑每项的文本/名称. 要编辑某项, 选择它接着按下 F2 键. 或者, 你可以对一个项目点击一次来选择它, 至少等待半秒钟, 然后再次点击同一项目进行编辑. 编辑后, 一个项目可以在其同级项目之间按字母顺序重新定位, 请参考下面的例子:

    Gui, Add, TreeView, -ReadOnly gMyTree
    ; ...
    MyTree:
    if (A_GuiEvent == "e")  ; The user has finished editing an item (use == for case sensitive comparison).
        TV_Modify(TV_GetParent(A_EventInfo), "Sort")  ; This works even if the item has no parent.
    return

R: 行高 (创建时).指定字母 R 接着为在控件中留出空间的行数. 例如, R10 将使控件为 10 个项目的高度.

WantF2: 指定 -WantF2 (负 WantF2) 来禁止使用 F2 键击 编辑 当前选择的项目. 仅当 -ReadOnly 也有效时此设置才不会被忽略.不论此设置如何, g-label 仍会接收到 F2 通告.

(未命名的数字样式): 由于上述以外的其他样式很少使用, 它们没有名称.参见 TreeView 样式表 了解这些样式.

## TreeViews 中的内置函数

所有的 TreeView 函数操作于当前线程的 默认 GUI 窗口 (这可以通过 Gui, 2:Default 改变). 如果默认窗口不存在或不含有 TreeView 控件, 所有函数返回 0 来表明此问题.

如果窗口含有多个 TreeView 控件, 默认情况下函数操作于最近添加的那个. 要改变这种情况, 请指定 Gui, TreeView, TreeViewName, 此处 TreeViewName 为 TreeView 的 关联变量 的名称或 Window Spy 中显示的其 ClassNN. 一旦改变后, 所有现有和将来的 线程 将使用指定的 TreeView.

## 添加, 修改, 和删除项目

TV_Add(Name, [ParentItemID, Options]): 添加一个新项到 TreeView 并且返回其唯一的 项目 ID 号 (当失败时返回 0). Name 为被显示的项目文本, 其可以为文本或数字 (包括数值的 表达式 结果). ParentItemID 为新项目的父项的 ID 号 (忽略它或指定 0 来添加项目到顶级). 当添加大量项目时, 在添加项目前使用 GuiControl, -Redraw, MyTreeView 并且在添加项目后使用 GuiControl, +Redraw, MyTreeView 可以提升性能.

TV_Add() 和 TV_Modify() 的选项: 选项 参数是一个包含零个或多个下面列表中单词的字符串 (不区分大小写). 单词间使用空格或制表符分隔.要移除一个选项, 请在选项前加上一个负号.要添加一个选项, 可以在选项前加上一个正号但不是必需的.

Bold: 用粗体显示项目的名称. 要在以后取消项目名称的粗体显示, 请使用 TV_Modify(ItemID, "-Bold").

Check: 在项目的左边显示一个复选标记 (需要 TreeView 含有 复选框). 要在以后取消复选它, 请使用 TV_Modify(ItemID, "-Check"). 在单词 Check 后可选跟着一个 0 或 1 来表示初始状态. 换言之, "Check" 和 "Check" . VarContainingOne 是相同的 (这里中间使用的是 连接运算符).

Expand: 展开此项目来显示其子项目 (如果有的话). 以后要折叠项目, 请使用 TV_Modify(ItemID, "-Expand"). 如果没有子项目, TV_Modify() 返回 0 而不是项目 ID. 相比之下, TV_Add() 标记此项目为展开的以防以后要添加子项目. 与 "Select" (下面的) 不同, 展开一个项目不会自动展开其父项目. 最后, 在单词 Expand 后可选跟着一个 0 或 1 来表示初始状态. 换言之, "Expand" 和 "Expand" . VarContainingOne 是相同的.

First | Sort | N: 这些选项仅适用于 TV_Add(). 它们指定新项目相对于其同级项目的位置 (此处 同级项目 是同一级别的其他任何项目). 如果这些选项都不存在, 新项目被添加到同级项目的最后一个/底部. 否则, 指定 First 添加项目到同级项目的第一个/顶部, 或指定 Sort 按字母顺序插入新项目到同级项目中间. 如果指定一个普通的整数 (N), 则假定为同级项目的 ID 号, 新项目在其后插入 (如果整数 N 是唯一存在的选项, 它不需要包含在引号中).

Icon: 指定单词 Icon 接着此项目图标的编号, 项目图标显示在项目名称的左边. 如果此选项不存在, 则使用 ImageList 中的首个图标.要显示一个空白图标, 指定一个大于 ImageList 中图标编号的数字.如果控件没有 ImageList, 则既不显示图标也不为图标保留空间.

Select: 选择项目. 因为一次只能选择一个项目, 此时任何原来选择的项目会自动取消选择. 此外, 如果有必要此选项会展开其父项目以显示新选择的项目. 要找出当前的选择, 请调用 TV_GetSelection().

Sort: 对于 TV_Modify(), 此选项按字母顺序排列指定项目的子项目. 要排序所有顶级项目, 请使用 TV_Modify(0, "Sort"). 如果不含子项目, 返回 0 而不是所修改的项目 ID.

Vis: 通过滚动 TreeView 和/或展开其父项目 (如果必要) 确保此项完全可见.

VisFirst: 和上面一样, 除了滚动 TreeView 使得此项显示在最上面, 如果可能的话. 此选项与 TV_Modify() 一起使用比与 TV_Add() 通常更有效.

TV_Modify(ItemID [, Options, NewName]): 修改一个项目的属性和/或名称. 成功时它返回项目自己的 ID 而失败 (或部分失败) 时返回 0. 如果仅存在首个参数, 则 选择 指定的项目. 如果省略 NewName, 则当前名称保持不变. 了解 选项, 参见上面的列表.

TV_Delete([ItemID]): 如果省略 ItemID, 则删除 TreeView 中 所有 项目. 否则, 仅删除指定 ItemID 所在的项目. 成功时返回 1 而失败返回 0.

## 从 TreeView 中获取数据

TV_GetSelection(): 返回选择项目的 ID 号.

TV_GetCount(): 返回控件中项目的总数. 此函数总是即时的因为控件跟踪此计数.

TV_GetParent(ItemID): 返回指定项目的父项目的 ID. 顶级项目没有父项目因此返回 0.

TV_GetChild(ParentItemID): 返回指定项目的第一个/最上面的 子项目的 ID 号 (如果没有则为 0).

TV_GetPrev(ItemID): 返回指定项目上面一个的同级项目的 ID 号 (如果没有则为 0).

TV_GetNext([ItemID, "Checked | Full"]): 此函数含有以下模式:

1. 省略所有参数时, 它返回 TreeView 中第一个/最上面的项目的 ID 号 (如果没有则为 0).
2. 如果仅存在首个参数 (ItemID), 它返回指定项目下面一个的同级项目的 ID 号 (如果没有则为 0). 如果首个参数为 0, 它返回 TreeView 中第一个/最上面的项目的 ID 号 (如果没有则为 0).
3. 当第二个参数为 "Full" 或 "F", 则获取下一个项目, 不论是否是指定项目的同级项目. 这使得脚本可以容易的逐项遍历整个树. 例如:

       ItemID = 0  ; Causes the loop's first iteration to start the search at the top of the tree.
       Loop
       {
           ItemID := TV_GetNext(ItemID, "Full")  ; Replace "Full" with "Checked" to find all checkmarked items.
           if not ItemID  ; No more items in tree.
       break
           TV_GetText(ItemText, ItemID)
           MsgBox The next Item is %ItemID%, whose text is "%ItemText%".
       }

4. 当第二个参数为 "Check", "Checked", 或 "C", 与上面行为相同, 除了跳过任何没有复选标记的项目. 这使得可以逐个获取 TreeView 中所有含有复选标记的项目.

TV_GetText(OutputVar, ItemID): 获取指定 ItemID 的文本/名称并保存到 OutputVar 中. 如果文本长于 8191, 则仅获取开始的 8191 个字符.成功时函数返回项目自己的 ID. 失败时返回 0 (并且 OutputVar 也被置空).

TV_Get(ItemID, "Expand | Check | Bold"): 如果指定的项目含有指定的属性, 则返回其自己的 ItemID. 否则返回 0. 在第二个参数中指定 "E", "Expand", 或 "Expanded" 以判断此项当前是 展开的 (即其子项目是显示的); 指定 "C", "Check", 或 "Checked" 以判断此项含有 复选标记; 或指定 "B" 或 "Bold" 以判断此项当前为 粗体 显示.

提示: 因为在 IF声明 中把任何非零值视为 "真", 下面两行功能相同:

1. if TV_Get(ItemID, "Checked") = ItemID
2. if TV_Get(ItemID, "Checked")

## G-Label 通告 (主要)

一个 g-label 例如 gMySubroutine 可以使用在此控件选项中. 这使得当用户在控件中执行一个动作时 MySubroutine 标签会自动运行. 此子程序中可参考使用内置变量 A_Gui 和 A_GuiControl 来找出哪个窗口和 TreeView 产生的事件. 更重要的是, 它可以参考 A_GuiEvent, 其包含下列字符串或字母的其中一个 (考虑到和未来版本的兼容性, 一个脚本不应假定这些字符串或字母是唯一可能的值):

DoubleClick: 用户双击了一项. 变量 A_EventInfo 包含目标项目 ID.

D: 用户尝试开始拖动一个项目 (目前还没有内置对拖动项目的支持). 变量 A_EventInfo 包含目标项目 ID.

d (小写的 D): 和上面相同, 除了指右键拖动而不是左键拖动.

e (小写的 E): 用户完成编辑一个项目 (只有当 TreeView 选项中含有 -ReadOnly 时用户才可以编辑项目). 变量 A_EventInfo 包含目标项目 ID.

S: 选择了一个新项目, 由用户或脚本自己选择的. 变量 A_EventInfo 包含新选择项目的 ID.

## G-Label 通告 (次要)

如果 TreeView 的 选项 中含有单词 AltSubmit, 其 g-label 会运行的更频繁并且 A_GuiEvent 可能包含下列附加的值:

Normal: 用户左键单击了一个项目.变量 A_EventInfo 包含目标项目 ID.

RightClick: 用户右键单击了一个项目. 变量 A_EventInfo 包含了目标项目 ID. 在大多数情况下, 最好不要显示一个菜单响应此通告. 而是使用 GuiContextMenu 标签 因为它还能识别 Appskey.例如:

    GuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
    if A_GuiControl <> MyTreeView  ; This check is optional. It displays the menu only for clicks inside the TreeView.
        return
    ; Show the menu at the provided coordinates, A_GuiX and A_GuiY.  These should be used
    ; because they provide correct coordinates even if the user pressed the Apps key:
    Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
    return

E: 用户开始编辑一个项目 (只有当 TreeView 选项中含有 -ReadOnly 时用户才可以编辑项目). 变量 A_EventInfo 包含目标项目 ID.

F: TreeView 接收到键盘焦点.

f (小写的 F): TreeView 失去了键盘焦点.

K: 当 TreeView 拥有焦点时用户按下了一个键. A_EventInfo 包含此键的虚拟按键代码, 它是介于 1 和 255 之间的一个数字.如果此键是字母键, 在大多数键盘布局中可以通过 Chr(A_EventInfo) 把它转换成相应的字符.不论 WantF2 如何都会接收到 F2 键击. 然而, 不会接收到 Enter 键击; 要接收它, 像 下面 描述的那样使用一个默认按钮.

+ (加号): 展开了一个项目以显示其子项目. 变量 A_EventInfo 包含目标项目 ID.

- (减号): 折叠了一个项目以隐藏其子项目. 变量 A_EventInfo 包含目标项目 ID.

## 备注

Gui Submit 命令对 TreeView 控件没有效果. 因此, 脚本可以使用 TreeView 的 关联变量 (如果有的话) 来保存其他数据而不用担心它会被覆盖.

当 TreeView 拥有焦点时如果要检测到用户按下的回车键, 请使用一个 默认按钮 (如果需要可以隐藏它). 例如:

    Gui, Add, Button, Hidden Default, OK
    ...
    ButtonOK:
    GuiControlGet, FocusedControl, FocusV
    if FocusedControl <> MyTreeView
        return
    MsgBox % "Enter was pressed. The selected item ID is " . TV_GetSelection()
    return

为了用键盘在项与项之间导航, 用户还可以通过输入一个项目名称的前几个字符来执行增量搜索. 这使得选择对象跳转到最近匹配的项目.

尽管 TreeView 中的每个项目可以存储任何长度的文本, 但仅显示开始的 260 个字符.

尽管理论上 TreeView 中可以使用最大的项目数为 65536, 接近此数目时添加项的性能将显著降低. 通过使用 TV_Add() 中描述的重绘提示可以稍微减轻这种情况.

与 ListViews 不同, 当 TreeView 销毁时其 ImageList 不会被自动销毁. 因此, 如果 TreeView 中使用的 ImageList 以后不再用于其他地方, 在销毁 TreeView 所在的窗口后脚本应该调用 IL_Destroy(ImageListID) 销毁此 ImageList. 然而, 如果脚本很快将退出这样做是没必要的因为那时所有的 ImageList 会被自动销毁. 相关提示, TreeView 最初的 ImageList 可以被替换为一个新的, 参照此例:

    Gui +LastFound
    SendMessage, 0x1109, 0, NewImageListID, SysTreeView321  ; 0x1109 is TVM_SETIMAGELIST
    if ErrorLevel  ; The TreeView had a previous ImageList.
        IL_Destroy(ErrorLevel)  ; Destroying it is the most typical action.

一个脚本可以在每个窗口中创建多个 TreeView. 要对非默认的 TreeView 进行操作, 请参见 内置函数.

要执行一些操作例如调整大小, 隐藏或改变 TreeView 的字体, 请使用 GuiControl.

Tree View eXtension (TVX) 扩展了 TreeViews 的功能增加支持移动, 插入和删除. 演示的例子参见 www.autohotkey.com/forum/topic19021.html

Windows 95 和 NT4: 如果系统缺少后面这些文件的 4.70 或更高版本: Comctl32.dll, Shell32.dll, and Shlwapi.dll -- 它们随各种更新和应用程序例如 Internet Explorer 3.0 或更高版本一起发布 -- TreeView 的功能受到更多限制并且某些特性可能不会和预期一样.

## 相关

ListView, 其他控件类型, Gui, GuiContextMenu, GuiControl, GuiControlGet, TreeView 样式表

## 示例

    ; The following is a working script that is more elaborate than the one near the top of this page.
    ; It creates and displays a TreeView containing all folders in the all-users Start Menu.  When the
    ; user selects a folder, its contents are shown in a ListView to the right (like Windows Explorer).
    ; In addition, a StatusBar control shows information about the currently selected folder.

    ; The following folder will be the root folder for the TreeView. Note that loading might take a long
    ; time if an entire drive such as C:\ is specified:
    TreeRoot = %A_StartMenuCommon%
    TreeViewWidth := 280
    ListViewWidth := A_ScreenWidth - TreeViewWidth - 30

    ; Allow the user to maximize or drag-resize the window:
    Gui +Resize

    ; Create an ImageList and put some standard system icons into it:
    ImageListID := IL_Create(5)
    Loop 5  ; Below omits the DLL's path so that it works on Windows 9x too:
        IL_Add(ImageListID, "shell32.dll", A_Index)

    ; Create a TreeView and a ListView side-by-side to behave like Windows Explorer:
    Gui, Add, TreeView, vMyTree r20 w%TreeViewWidth% gMyTree ImageList%ImageListID%
    Gui, Add, ListView, vMyList r20 w%ListViewWidth% x+10, Name|Modified

    ; Set the ListView's column widths (this is optional):
    Col2Width = 70  ; Narrow to reveal only the YYYYMMDD part.
    LV_ModifyCol(1, ListViewWidth - Col2Width - 30)  ; Allows room for vertical scrollbar.
    LV_ModifyCol(2, Col2Width)

    ; Create a Status Bar to give info about the number of files and their total size:
    Gui, Add, StatusBar
    SB_SetParts(60, 85)  ; Create three parts in the bar (the third part fills all the remaining width).

    ; Add folders and their subfolders to the tree. Display the status in case loading takes a long time:
    SplashTextOn, 200, 25, TreeView and StatusBar Example, Loading the tree...
    AddSubFoldersToTree(TreeRoot)
    SplashTextOff

    ; Display the window and return. The OS will notify the script whenever the user performs an eligible action:
    Gui, Show,, %TreeRoot%  ; Display the source directory (TreeRoot) in the title bar.
    return

    AddSubFoldersToTree(Folder, ParentItemID = 0)
    {
        ; This function adds to the TreeView all subfolders in the specified folder.
        ; It also calls itself recursively to gather nested folders to any depth.
        Loop %Folder%\*.*, 2  ; Retrieve all of Folder's sub-folders.
            AddSubFoldersToTree(A_LoopFileFullPath, TV_Add(A_LoopFileName, ParentItemID, "Icon4"))
    }

    MyTree:  ; This subroutine handles user actions (such as clicking).
    if A_GuiEvent <> S  ; i.e. an event other than "select new tree item".
        return  ; Do nothing.
    ; Otherwise, populate the ListView with the contents of the selected folder.
    ; First determine the full path of the selected folder:
    TV_GetText(SelectedItemText, A_EventInfo)
    ParentID := A_EventInfo
    Loop  ; Build the full path to the selected folder.
    {
        ParentID := TV_GetParent(ParentID)
        if not ParentID  ; No more ancestors.
            return
        TV_GetText(ParentText, ParentID)
        SelectedItemText = %ParentText%\%SelectedItemText%
    }
    SelectedFullPath = %TreeRoot%\%SelectedItemText%

    ; Put the files into the ListView:
    LV_Delete()  ; Clear all rows.
    GuiControl, -Redraw, MyListView  ; Improve performance by disabling redrawing during load.
    FileCount = 0  ; Init prior to loop below.
    TotalSize = 0
    Loop %SelectedFullPath%\*.*  ; For simplicity, this omits folders so that only files are shown in the ListView.
    {
        LV_Add("", A_LoopFileName, A_LoopFileTimeModified)
        FileCount += 1
        TotalSize += A_LoopFileSize
    }
    GuiControl, +Redraw, MyListView

    ; Update the three parts of the status bar to show info about the currently selected folder:
    SB_SetText(FileCount . " files", 1)
    SB_SetText(Round(TotalSize / 1024, 1) . " KB", 2)
    SB_SetText(SelectedFullPath, 3)
    return

    GuiSize:  ; Expand/shrink the ListView and TreeView in response to user's resizing of window.
    if A_EventInfo = 1  ; The window has been minimized.  No action needed.
        return
    ; Otherwise, the window has been resized or maximized. Resize the controls to match.
    GuiControl, Move, MyTree, % "H" . (A_GuiHeight - 30)  ; -30 for StatusBar and margins.
    GuiControl, Move, MyList, % "H" . (A_GuiHeight - 30) . " W" . (A_GuiWidth - TreeViewWidth - 30)
    return

    GuiClose:  ; Exit the script when the user closes the TreeView's GUI window.
    ExitApp