# ListView

## 目录

- 入门和简单示例
- 选项和样式
- 视图模式: Report (默认), Icon, Tile, Small-Icon, 和 List.
- 内置函数:
  - 行函数 (添加, 修改, 和删除行)
  - 列函数
  - 从 ListView 中获取数据
- G-Label 通告
- ImageLists (通过它把图标添加到 ListView 的方法)
- ListView 备注
- 示例

## 入门和简单示例

List-View 是由操作系统提供的最精心设计的控件之一. 在其最容易识别的形式中, 它显示一个多行多列组成的表格视图, 最常见的例子是资源管理器的文件和文件夹列表 (详细信息视图).

尽管它可能是精细的, ListView 的基本特性也易于使用. 创建 ListView 的语法为:

Gui, Add, ListView, Options, ColumnTitle1|ColumnTitle2|...

这里是一个工作的脚本, 它创建和显示包含用户 "我的文档" 目录中文件的列表的 ListView:

    ; Create the ListView with two columns, Name and Size:
    Gui, Add, ListView, r20 w700 gMyListView, Name|Size (KB)

    ; Gather a list of file names from a folder and put them into the ListView:
    Loop, %A_MyDocuments%\*.*
        LV_Add("", A_LoopFileName, A_LoopFileSizeKB)

    LV_ModifyCol()  ; Auto-size each column to fit its contents.
    LV_ModifyCol(2, "Integer")  ; For sorting purposes, indicate that column 2 is an integer.

    ; Display the window and return. The script will be notified whenever the user double clicks a row.
    Gui, Show
    return

    MyListView:
    if A_GuiEvent = DoubleClick
    {
        LV_GetText(RowText, A_EventInfo)  ; Get the text from the row's first field.
        ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
    }
    return

    GuiClose:  ; Indicate that the script should exit automatically when the window is closed.
    ExitApp

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

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

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

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

Checked: 在每行的左侧提供一个复选框. 当 添加 一行时, 在其选项中指定单词 Check 使复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中一行.

Count: 指定单词 Count 接着 ListView 最后将包含的总行数. 这不是限制: 超过此数目后仍然可以添加行. 相反, 此选项给控件一个暗示, 允许它一次性的分配内存而不是每次添加一行时, 这样极大的提高添加行时的性能 (这也可以提高排序性能). 为了提升更多的性能, 请在添加大量行前使用 GuiControl, -Redraw, MyListView. 随后, 使用 GuiControl, +Redraw, MyListView 来重新启用重绘 (这样也重绘了控件).

Grid: 提供水平的和垂直的线以形象的显示出行与行和列与列之间的边界.

Hdr: 指定 -Hdr (minus Hdr) 来隐藏包含列标题的特殊顶行. 后来要使它可见, 请使用 GuiControl, +Hdr, MyListView.

LV: 指定字符串 LV 接着 扩展的 ListView 样式 中的数字. 这些样式完全独立于通用扩展样式. 例如, 指定 -E0x200 将移除通用扩展样式 WS_EX_CLIENTEDGE 来去除控件的默认边框. 相比之下, 指定 -LV0x20 将移除 LVS_EX_FULLROWSELECT.

LV0x10: 指定 -LV0x10 防止用户通过拖动列标题到左边或右边来对它们重新排序. 然而, 通常没必要这么做因为列的实际重排不会影响脚本看到的列顺序. 例如, 从脚本的观点看第一列将总是 column 1, 即使用户实际已经把它移动到其他列的右边.

LV0x20: 指定 -LV0x20 来要求点击一行的第一个区域才可以选择它 (正常情况下点击在 任一 区域都将选择它). 这样的好处是用户可以更方便的绕着一组行拖动矩形来选择他们.

Multi: 指定 -Multi (负 Multi) 禁止用户一次选择多行.

NoSortHdr: 禁止点击标题. 此时将显示平坦的外观而不是正常的类似按钮的外观. 与其他大多数 ListView 样式不同, 此样式在 ListView 创建后无法改变.

NoSort: 关闭当用户点击列标题时发生的自动排序. 然而, 标题的外观看提来仍像按钮 (除非指定了 NoSortHdr).此外, g-label 仍将接收到 ColClick 通告, 对此它可以用自定义排序或其他操作来响应.

ReadOnly: 指定 -ReadOnly (负 ReadOnly) 来允许编辑每行首列的文本. 要编辑某行, 选择它接着按下 F2 键. 或者, 你可以对一行点击一次来选择它, 至少等待半秒钟, 然后再次点击同一行进行编辑.

R: 行高 (创建时). 指定字母 R 接着为行在控件中留出空间的数目. 例如, R10 将使控件 10 行的高度. 如果 ListView 使用报告视图外的其他 视图模式 创建, 控件会调整大小以适应含图标的行而不是文本行. 注: 添加 图标 到 ListView 的行中将增加每行的高度, 这将使得此选项不准确.

Sort: 控件根据首列的内容保持按字母顺序排列.

SortDesc: 和上面一样, 除了按降序排列.

WantF2 [v1.0.44+]: 指定 -WantF2 (负 WantF2) 来禁止使用 F2 键击 编辑 当前焦点行. 仅当 -ReadOnly 也有效时此设置才不会被忽略. 不论此设置如何, g-label 仍会接收到 F2 通告.

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

## 视图模式

ListView 有五种视图模式, 其中最常见的是报告视图 (这是默认模式). 要使用一种其他视图, 请在选项列表中指定其名称. 也可以在控件创建后改变视图模式; 例如: GuiControl, +IconSmall, MyListView

Icon: 显示大图标视图. 在此视图和除 Report 外的所有其他视图中, 仅首列中的文本才可见. 要在此模式中显示图标, ListView 必须分配有一个含有大图标 ImageList.

Tile: 显示大图标视图但具有人体工学差异, 例如显示每项的文本在图标的右边而不是下面. Checkboxe 不能使用于此视图中. 此外, 尝试在比 Windows XP 更低版本的操作系统中显示此视图没有效果.

IconSmall: 显示小图标视图.

List: 以列表格式显示小图标视图, 其中图标显示在列中. 列的数目取决于控件的宽度和控件中最宽文本项目的宽度.

Report: 切换回报告视图, 这是最初的默认模式. 例如: GuiControl, +Report, MyListView

## ListView 中的内置函数

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

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

当在此页面使用短语 "row number", 它指的是 ListView 中行的当前位置. 最上面一行为 1, 第二行为 2, 依此类推. 添加一行后, 其行号会因为排序, 删除和插入其他行而发生变化. 因此, 要根据内容查找特定的一行或多行, 通常最好在循环中使用 LV_GetText().

## 行函数

LV_Add([Options, Field1, Field2, ...]): 添加一个新行到列表底部. 参数 Field1 和其后的字段是新行的列内容, 可以是文本或数字 (包括数值的 表达式 结果). 要使任何字段为空, 请指定 "" 或等价物. 如果参数中太少字段而无法填满所有列, 后面剩下的列被留空. 如果太多字段, 后面多出的字段被忽略.

失败时, LV_Add() 返回 0. 成功时, 它返回新 行号, 如果 ListView 含有 Sort 或 SortDesc 样式则此行不一定是最后一行.

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

Check: 在行中显示一个选中标记 (需要 ListView 含有 复选框). 要在以后取消选中它, 请使用 LV_Modify(RowNumber, "-Check").

Col: 指定单词 Col 接着列号, 从此列开始往后应用参数 Col1 和其后参数的内容. 此选项通常和 LV_Modify() 一起使用来修改行中个别字段, 不会影响它们左边的那些字段.

Focus: 设置键盘焦点到此行 (通常和 Select 一起使用). 要在以后取消它的焦点, 请使用 LV_Modify(RowNumber, "-Focus").

Icon: 指定单词 Icon 接着这行图标的编号, 这行图标显示在首列的左侧. 如果此选项不存在, 则使用 ImageList 中的首个图标. 要显示一个空白图标, 指定一个大于 ImageList 中图标编号的数字. 如果控件没有小图标 ImageList, 则 报告视图 中既不显示图标也不为其保留空间.

Select: 选择行. 要在以后取消选择, 请使用 LV_Modify(RowNumber, "-Select"). 当选择行时, 通常最好确保至少有一行总含有 焦点属性 因为这样允许 Appskey 在焦点行附近显示其 上下文菜单 (如果有的话).在单词 Select 后面可选跟着一个 0 或 1 来表示初始状态. 换言之, "Select" 和 "Select" . VarContainingOne 是相同的 (这里中间使用的是 连接运算符). 此方法也适用于上面的 Focus 和 Check.

Vis [1.0.44+]: 必要时通过滚动 ListView 确保指定行完全可见. 此参数仅对 LV_Modify() 有效; 例如: L V_Modify(RowNumber, "Vis")

LV_Insert(RowNumber [, Options, Col1, Col2, ...]): 与 LV_Add() 行为一样, 除了其首个参数的不同, 它指定了新插入行的行号. 任何在 RowNumber 上或其下方的行往下移来为新行腾出空间. 如果 RowNumber 大于列表中行的数目 (甚至可以高达 2147483647), 新行被添加到列表的底部. 想了解 选项, 请参见 行选项.

LV_Modify(RowNumber, Options [, NewCol1, NewCol2, ...]): 修改行的属性和/或文本, 成功时返回 1 而失败时返回 0. 如果 RowNumber 为 0, 则修改控件中 所有 行 (此时如果操作完全成功返回 1 而部分失败时返回 0). 当只存在前两个参数时, 仅修改行的属性而不改变其文本. 同样, 如果参数太少无法覆盖所有列, 后面剩下的列保持不变. ColN 选项 可以用来更新指定的列而不影响其他列. 关于其他选项, 请参见 行选项.

LV_Delete([RowNumber]): 如果省略参数, 则删除 ListView 中 所有 行. 否则, 仅删除指定 RowNumber 所在的行. 成功时返回 1 而失败返回 0.

## 列函数

LV_ModifyCol([ColumnNumber, Options, ColumnTitle]): 修改指定列的属性和/或文本和它的标题. 首列编号为 1 (不是 0). 如果省略所有参数, 则调整所有列的宽度以适应行的内容. 如果仅存在首个参数, 则仅自动调整指定列的大小. 只有在报告(详细信息)视图中时自动调整大小才有效果. 此函数成功时返回 1 而失败时返回 0.

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

列选项: 常规

N: 指定 N 为列的新宽度, 单位为像素. 如果是唯一的选项, 此数字可以不带引号. 例如, 后面的两种形式都是有效的: LV_ModifyCol(1, 50) .... LV_ModifyCol(1, "50 Integer").

Auto: 调整列宽来适应其内容. 只有在报告(详细信息)视图中此选项才有效果.

AutoHdr: 调整列宽来适应其内容和列标题文本, 以较宽的为准. 当应用于最后一列时, 它将被设置为至少和 ListView 中剩余空间的宽度一样. 通常最好仅在行已经添加后才应用此设置, 因为这样允许当调整最后一列的大小时考虑到可能新增加的垂直滚动栏. 只有在报告(详细信息)视图中此选项才有效果.

Icon: 指定单词 Icon 接着 ImageList 中图标的编号然后是列标题文本. 指定 -Icon (负 icon) 来移除任何现有的图标. 在 Windows 95/NT4 系统中, 需要与 Internet Explorer 3.0 或更高版本一起发布的 DLL 文件才能支持列图标.

IconRight: 把图标放在列的右边而不是左边.

列选项: 数据类型

Float: 用于排序的目的, 指明此列包含浮点数 (不支持十六进制格式). 浮点数和文本列的排序性能最多可能比整数列的慢 25 倍.

Integer: 用于排序的目的, 指明此列包含整数. 为了能正确的排序, 每个整数必须是 32 位的; 即在范围 -2147483648 到 2147483647 内. 任何非整数的值在排序时将被视为零 (除非这些值以一个数字开始, 此时使用这个数字). 数字格式可以为十进制或十六进制 (例如 0xF9E0).

Text: 更改列返回到文本模式排序, 这是每列初始默认的排序方式. 在排序时仅有文本开始的 8190 个字符是有意义的 (除非使用了 Logical 选项, 此时限制为 4094).

列选项: 对齐 / 字距调整

Center: 让文本居于列中央. 要让整数或浮点数列居中, 请在单词 Integer 或 Float 后指定单词 Center.

Left: 让列文本左对齐, 这是每列初始默认的对齐方式. 在较旧版本的操作系统上, 首列可能会强制进行左对齐.

Right: 让列文本右对齐. 对于整数和浮点数列不需要指定此属性因为它们默认是右对齐的. 通过指定例如 "Integer Left" or "Float Center" 的字符串可以覆盖此默认的对齐方式.

列选项: 排序

Case: 列排序区分大小写 (仅影响 文本 列). 如果选项 Case, CaseLocale, 和 Logical 都省略, 在排序中大写字母 A-Z 被视为等同于它们相应的小写形式.

CaseLocale [v1.0.43.03+]: 列排序基于当前用户的区域设置并且不区分大小写 (仅影响 文本 列). 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母例如 ? 和 ü 等同于它们的小写形式.这种方法也使用"单词排序", 它把单词中的连字符和撇号例如 "coop" 和 "co-op" 保持在一起.

Desc: 降序排列. 用户首次对此列排序时使用下降的顺序.

Logical [v1.0.44.12+]: 与 CaseLocale 相同, 除了把文本中的任何数字位序列看成真正的数字而不仅仅字符. 例如, 字符串 T33 将被视为大于 T4. Logical 需要 Windows XP 或更高版本的系统才支持 (在较旧的操作系统中, 自动使用 CaseLocale 代替). 此外, Logical 和 Case 是互斥的: 只有最近指定的那个才有效.

NoSort: 防止用户点击此列而对自动排序产生任何的影响.要禁用所有列的排序而不仅是其中的子集, 请在 ListView 的选项中包含 NoSort. 如果 ListView 含有 g-label, 当用户点击 no-sort 的列时仍将接收到 ColClick 通告.

Sort: 立即对列按升序排列 (即使含有 Desc 选项).

SortDesc: 立即对列按降序排列.

Uni: 单向排序. 此选项防止在相同列进行第二次点击来反转排序方向.

LV_InsertCol(ColumnNumber [, Options, ColumnTitle]): 创建一个新列, 以指定的 ColumnNumber 插入 (转移其他的列到右边来腾出空间). 首列编号为 1 (不是 0). 如果 ColumnNumber 大于当前控件中列的数目, 新列被添加到列表的底部. 新插入的列开始时内容是空的除非它是首列, 此时它继承原来首列的内容, 而原来首列的内容变为空的. 新列的属性 -- 例如是否使用 整数排序 -- 开始时总为它们的默认值除非使用了 选项 改变. 此函数返回新列的位置编号 (当失败时返回 0). ListView 中的最大列数是 200.

LV_DeleteCol(ColumnNumber): 删除指定的列和其中的所有内容. 成功时返回 1 而失败返回 0.当一个列被删除后, 在此列右边的任何列的编号减 1. 因此, 调用 LV_DeleteCol(2) 两次将删除第二列和第三列. 在比 Windows XP 老的操作系统中, 试图删除原始的首列可能会失败并返回 0.

## 从 ListView 中获取数据

LV_GetCount(["Selected | Column"]): 省略参数时, 函数返回控件中总行数. 当参数为 "S" 或 "Selected" 时, 计数仅包括选择的/高亮的行.当参数为 "Col" 或 "Column", 函数返回控件中的列数.此函数总是即时的因为控件跟踪这些计数.

此函数常用于一个循环的顶行, 此时将仅调用一次函数 (在首次循环前).例如:

    Loop % LV_GetCount()
    {
        LV_GetText(RetrievedText, A_Index)
        if InStr(RetrievedText, "some filter text")
            LV_Modify(A_Index, "Select")  ; Select each row whose first field contains the filter-text.
    }

为了获取 ListView 的列宽 -- 用于例如保存它们到 INI 文件来在会话间保持一致 -- 请参照此例:

    Gui +LastFound
    Loop % LV_GetCount("Column")
    {
        SendMessage, 4125, A_Index - 1, 0, SysListView321  ; 4125 is LVM_GETCOLUMNWIDTH.
        MsgBox Column %A_Index%'s width is %ErrorLevel%.
    }

LV_GetNext([StartingRowNumber, "Checked | Focused"]): 返回下一个选择的, 选中的或焦点行的行号. 如果没有找到, 则返回零.如果 StartingRowNumber 省略或小于 1, 则从列表顶部开始搜索.否则, 从 StartingRowNumber 行后开始搜索.如果省略第二个参数, 则函数搜索下一个选择的/高亮的行.否则, 指定 "C" 或 "Checked" 来寻找下一个选中的行; 或指定 "F" 或 "Focused" 来寻找焦点行 (在整个列表中不可能有多个焦点行, 而有时可能没有).下面的示例报告 ListView 中所有选择的行:

    RowNumber = 0  ; This causes the first loop iteration to start the search at the top of the list.
    Loop
    {
        RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
        if not RowNumber  ; The above returned zero, so there are no more selected rows.
            break
        LV_GetText(Text, RowNumber)
        MsgBox The next selected row is #%RowNumber%, whose first field is "%Text%".
    }

判断一个特定的行是否被选中的另一种方法如下:

    Gui +LastFound
    SendMessage, 4140, RowNumber - 1, 0xF000, SysListView321  ; 4140 is LVM_GETITEMSTATE.  0xF000 is LVIS_STATEIMAGEMASK.
    IsChecked := (ErrorLevel >> 12) - 1  ; This sets IsChecked to true if RowNumber is checked or false otherwise.

LV_GetText(OutputVar, RowNumber [, ColumnNumber]): 获取在指定 RowNumber 和 ColumnNumber 上的文本并保存到 OutputVar 中. 如果省略 ColumnNumber, 默认值为 1 (首列的文本).如果 RowNumber 为 0, 则获取列标题文本.如果文本长于 8191, 则仅获取开始的 8191 个字符.此函数成功时返回 1 而失败时返回 0.失败时 OutputVar 也被置空.

用户可能已经完成的拖放操作不会修改脚本看到的列编号.例如, 最初的首列仍是 number 1 即使用户已经把它拖到其他列的右边.

## G-Label 通告 (主要)

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

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

R: 用户在控件内 双击了右键. 变量 A_EventInfo 包含了焦点行号.

ColClick: 用户点击了一个列标题. 变量 A_EventInfo 包含列编号, 这是当列创建时分配的原始编号; 即它不会反映任何用户对列完成的拖放操作. 列点击的一种可能的响应是通过一个包含排序友好格式 (例如一个 YYYYMMDD 整数日期) 数据的隐藏列 (零宽度) 进行排序. 这样的隐藏列可以境像其他列, 在那些列中使用更友好的格式显示相同的数据 (例如 MM/DD/YY). 例如, 一个脚本可以通过 LV_ModifyCol(3, 0) 隐藏 column 3, 接着通过 LV_ModifyCol(2, "NoSort") 关闭可见的 column 2 的自动排序. 然后响应 column 2 的 ColClick 通告, 脚本将使用隐藏的列通过 LV_ModifyCol(3, "Sort") 对 ListView 进行排序.

D: 用户尝试开始拖动行或图标 (目前还没有内置对拖动行或图标的支持). 变量 A_EventInfo 包含了焦点行号.在高于 1.0.44 的版本中, 即使不含 AltSubmit 选项此通告也会产生.

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

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

## G-Label 通告(次要)

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

Normal: 用户左键单击了一行. 变量 A_EventInfo 包含了焦点行号.

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

    GuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
    if A_GuiControl <> MyListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
        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

A: 激活了一行, 这种情况默认发生于双击一行时. 变量 A_EventInfo 包含目标行号.

C: ListView 释放了鼠标捕获.

E: 用户开始编辑一行的首个字段 (只有当 ListView 选项中含有 -ReadOnly 时用户才可以编辑它). 变量 A_EventInfo 包含目标行号.

F: ListView 接收到键盘焦点.

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

I:项目变化了. 通过变成选择的/未选择的, 选中的/未选中的等让一行改变了. 如果用户选择了一个新行, 至少会接收到两个这样的通告: 一个是取消选择之前的行, 而另一个是选择了新行. 在高于 1.0.44 的版本中, 变量 A_EventInfo 包含新行行号. 在高于 1.0.46.10 的版本中, ErrorLevel 包含零或多个下列字母以指出项目发生的变化: S (选择了) 或 s (取消选择), 和/或 F (成为焦点) 或 f (失去焦点), 和/或 C (选中了) 或 c (取消选中). 例如, SF 表示此行被选择了并且成为焦点. 要检查一个特定的字母是否存在, 请使用 解析循环 或 InStr() 的区分大小写选项; 例如: InStr(ErrorLevel, "S", true). 注: 考虑到和未来版本的兼容性, 一个脚本不应假定 "SsFfCc" 包含了所有可能的字母或字母组合. 此外, 指定 Critical 作为 g-label 子程序的首行来确保接收到所有的 "I" 通告 (否则, 如果脚本无法跟上它们其中一些可能丢失).

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

M: 选取框. 用户开始在一组行或图标周围拖动一个矩形选区.

S: 用户开始滚动 ListView.

s (小写的 S): 用户完成滚动 ListView.

## ImageList (通过它把图标添加到 ListView 的方法)

一个图像列表是保存在内存中的一组大小相同的图标. 创建后每个 ImageList 是空的. 脚本重复调用 IL_Add() 来添加图标到列表中, 并且每个图标分配到一个序号, 序号从 1 开始. 脚本引用此号码在一行中或列标题中显示一个特定的图标. 这里是一个有效的例子, 演示了如何让图标显示在 ListView 的行中:

    Gui, Add, ListView, h200 w180, Icon & Number|Description  ; Create a ListView.
    ImageListID := IL_Create(10)  ; Create an ImageList to hold 10 small icons.
    LV_SetImageList(ImageListID)  ; Assign the above ImageList to the current ListView.
    Loop 10  ; Load the ImageList with a series of icons from the DLL.
        IL_Add(ImageListID, "shell32.dll", A_Index)  ; Omits the DLL's path so that it works on Windows 9x too.
    Loop 10  ; Add rows to the ListView (for demonstration purposes, one for each icon).
        LV_Add("Icon" . A_Index, A_Index, "n/a")
    LV_ModifyCol("Hdr")  ; Auto-adjust the column widths.
    Gui Show
    return

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

IL_Create([InitialCount, GrowCount, LargeIcons?]): 创建一个新的 ImageList, 初始为空, 并且返回 ImageList 的唯一 ID (失败时返回 0). InitialCount 为希望马上放入列表的图标数 (如果省略, 默认为 2). GrowCount 为列表每次将增长时超出当前列表容量的图标数 (如果省略, 默认为 5). LargeIcons 应该是一个数值: 如果不为零, ImageList 将包含大图标. 如果为零, 它将包含小图标 (这是省略时的默认情况). 添加到列表中的图标会按比例自动缩放以符合系统中大小图标的尺寸.

LV_SetImageList(ImageListID [, 0|1|2]): 此函数一般在添加行到 ListView 之前调用. 它设置 ImageList 的关联, 其中的图标将显示在 ListView 的行中 (同时可选的, 它的列). ImageListID 为前面调用 IL_Create() 返回的数字. 如果省略第二个参数, 则自动检测 ImageList 中的图标作为大图标或小图标. 否则, 对于大图标指定 0, 小图标指定 1, 而状态图标指定 2 (还不能直接支持状态图标, 但可以通过 SendMessage 使用).

一个 ListView 最多可以关联两个 ImageList: 小图标和/或大图标. 当脚本允许用户在大图标视图和其他视图之间切换时这很有用. 为了再关联一个 ImageList 到 ListView, 再次调用 LV_SetImageList(), 其中指定第二个列表的 ImageListID. 同时关联有大图标和小图标 ImageList 的 ListView 应该确保在两个列表中包含的图标顺序相同. 这是因为使用一个指定图标的大小版本时引用相同的 ID 编号.

尽管除了 Icon 和 Tile 显示小图标外对于其他的 视图模式 这是惯例, 但通过传递一个大图标列表到 LV_SetImageList 并且在第二个参数中指定 1 (小图标) 可以覆盖此行为. 这也增加了 ListView 中每行的高度以适合大图标.

如果成功, LV_SetImageList() 返回之前与 ListView 关联的 ImageListID (如果没有则为 0). 任何分离的 ImageList 一般应该通过 IL_Destroy(ImageListID) 销毁.

IL_Add(ImageListID, Filename [, IconNumber, ResizeNonIcon?]): 添加一个图标或图片到指定的 ImageListID 并且返回新图标的索引 (首个图标索引为 1, 第二个为 2, 依此类推). Filename 是一个图标 (.ICO), 光标 (.CUR), 或动画光标 (.ANI) 文件的名称 (动画光标显示在 ListView 中时实际将不会动). 图标的其他来源包括下列文件类型: EXE, DLL, CPL, SCR, 和包含图标资源的其他类型.要使用文件中的图标组而不是首个图标, 请在 IconNumber 中指定其编号.在后面的例子中, 将使用第二个图标组中的默认图标: IL_Add(ImageListID, "C:\My Application.exe", 2).

非图标图像例如 BMP, GIF 和 JPG 也可以加载. 但是, 此时应该指定最后两个参数以确保正确的行为: IconNumber 应该为屏蔽的/透明的颜色编码 (对于大多数图片 0xFFFFFF [白色] 也许是最好的); 而 ResizeNonIcon 应该为非零值来缩放图片为单个图标, 或者为零来分割图像为多个可以匹配实际宽度的图标.

在所有的操作系统中都支持 GIF, JPG, BMP, ICO, CUR, 和 ANI 图像.在 Windows XP 或更高版本的系统中, 还支持其他图像格式例如 PNG, TIF, Exif, WMF, 和 EMF.通过复制微软的免费 GDI+ DLL 到 AutoHotkey.exe 文件夹中可以让 XP 之前的操作系统提供支持 (但如果是 已编译脚本, 则需要复制 DLL 到脚本的文件夹).要下载此 DLL, 请在 www.microsoft.com 中搜索下列短语: gdi redistributable

IL_Destroy(ImageListID): 删除指定的 ImageList, 成功时返回 1 而失败返回 0. 通常没必要销毁 ImageList, 因为一旦附加到 ListView, 当 ListView 或其父窗口销毁时它们会被自动销毁. 但是, 如果一个 ListView 和其他的 ListView 共享 ImageList (通过在选项中包含 0x40), 在所有使用此 ImageList 的 ListView 销毁后脚本应该明确的销毁它. 同样, 如果脚本使用一个新的 ImageList 代替 ListView 中原来的, 它应该明确的销毁原来的.

## ListView 备注

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

在对一个列排序后 -- 通过用户点击其标题的方法或脚本调用 LV_ModifyCol(1, "Sort") -- 任何随后添加的行将出现在列表的底部而不会服从排序顺序. 例外情况是 Sort 和 SortDesc 样式, 它们会把新行移到正确的位置.

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

    Gui, Add, Button, Hidden Default, OK
    ...
    ButtonOK:
    GuiControlGet, FocusedControl, FocusV
    if FocusedControl <> MyListView
        return
    MsgBox % "Enter was pressed. The focused row number is " . LV_GetNext(0, "Focused")
    return

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

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

尽管 ListView 中可以使用的最大行数仅受系统可用内存的限制, 但参照 Count 选项中所描述的方法可以极大提高添加行的性能.

可以使用一个图片作为 ListView 周围的背景 (即作为 ListView 的框架). 要做到这点, 在 ListView 后创建 图片控件 并且在图片控件的 选项 中包含 0x4000000 (这是 WS_CLIPSIBLINGS).

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

最好不要使用 SendMessage 直接插入或删除列. 这是因为程序为每列维护一个 排序参数 集, 这将使它们无法同步. 作为替代, 请使用 内置列函数.

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

要从外部的 ListView (不属于脚本的那些) 提取文本, 请使用 "ControlGet List".

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

## 相关

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

## 示例

    ; Select or de-select all rows by specifying 0 as the row number:
    LV_Modify(0, "Select")   ; Select all.
    LV_Modify(0, "-Select")  ; De-select all.
    LV_Modify(0, "-Check")  ; Uncheck all the checkboxes.

    ; Auto-size all columns to fit their contents:
    LV_ModifyCol()  ; There are no parameters in this mode.

?

    ; MAIN EXAMPLE
    ; The following is a working script that is more elaborate than the one near the top of this page.
    ; It displays the files in a folder chosen by the user, with each file assigned the icon associated with
    ; its type. The user can double-click a file, or right-click one or more files to display a context menu.

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

    ; Create some buttons:
    Gui, Add, Button, Default gButtonLoadFolder, Load a folder
    Gui, Add, Button, x+20 gButtonClear, Clear List
    Gui, Add, Button, x+20, Switch View

    ; Create the ListView and its columns:
    Gui, Add, ListView, xm r20 w700 vMyListView gMyListView, Name|In Folder|Size (KB)|Type
    LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.

    ; Create an ImageList so that the ListView can display some icons:
    ImageListID1 := IL_Create(10)
    ImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.

    ; Attach the ImageLists to the ListView so that it can later display the icons:
    LV_SetImageList(ImageListID1)
    LV_SetImageList(ImageListID2)

    ; Create a popup menu to be used as the context menu:
    Menu, MyContextMenu, Add, Open, ContextOpenFile
    Menu, MyContextMenu, Add, Properties, ContextProperties
    Menu, MyContextMenu, Add, Clear from ListView, ContextClearRows
    Menu, MyContextMenu, Default, Open  ; Make "Open" a bold font to indicate that double-click does the same thing.

    ; Display the window and return. The OS will notify the script whenever the user
    ; performs an eligible action:
    Gui, Show
    return

    ButtonLoadFolder:
    Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.
    FileSelectFolder, Folder,, 3, Select a folder to read:
    if not Folder  ; The user canceled the dialog.
        return

    ; Check if the last character of the folder name is a backslash, which happens for root
    ; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
    StringRight, LastChar, Folder, 1
    if LastChar = \
        StringTrimRight, Folder, Folder, 1  ; Remove the trailing backslash.

    ; Ensure the variable has enough capacity to hold the longest file path. This is done
    ; because ExtractAssociatedIconA() needs to be able to store a new filename in it.
    VarSetCapacity(Filename, 260)
    sfi_size = 352
    VarSetCapacity(sfi, sfi_size)

    ; Gather a list of file names from the selected folder and append them to the ListView:
    GuiControl, -Redraw, MyListView  ; Improve performance by disabling redrawing during load.
    Loop %Folder%\*.*
    {
        FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.

        ; Build a unique extension ID to avoid characters that are illegal in variable names,
        ; such as dashes.  This unique ID method also performs better because finding an item
        ; in the array does not require search-loop.
        SplitPath, FileName,,, FileExt  ; Get the file's extension.
        if FileExt in EXE,ICO,ANI,CUR
        {
            ExtID := FileExt  ; Special ID as a placeholder.
            IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
        }
        else  ; Some other extension/file-type, so calculate its unique ID.
        {
            ExtID = 0  ; Initialize to handle extensions that are shorter than others.
            Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
            {
                StringMid, ExtChar, FileExt, A_Index, 1
                if not ExtChar  ; No more characters.
                    break
                ; Derive a Unique ID by assigning a different bit position to each character:
                ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
            }
            ; Check if this file extension already has an icon in the ImageLists. If it does,
            ; several calls can be avoided and loading performance is greatly improved,
            ; especially for a folder containing hundreds of files:
            IconNumber := IconArray%ExtID%
        }
        if not IconNumber  ; There is not yet any icon for this extension, so load it.
        {
            ; Get the high-quality small-icon associated with this file extension:
            if not DllCall("Shell32\SHGetFileInfoA", "str", FileName, "uint", 0, "str", sfi, "uint", sfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
                IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
            else ; Icon successfully loaded.
            {
                ; Extract the hIcon member from the structure:
                hIcon = 0
                Loop 4
                    hIcon += *(&sfi + A_Index-1) << 8*(A_Index-1)
                ; Add the HICON directly to the small-icon and large-icon lists.
                ; Below uses +1 to convert the returned index from zero-based to one-based:
                IconNumber := DllCall("ImageList_ReplaceIcon", "uint", ImageListID1, "int", -1, "uint", hIcon) + 1
                DllCall("ImageList_ReplaceIcon", "uint", ImageListID2, "int", -1, "uint", hIcon)
                ; Now that it's been copied into the ImageLists, the original should be destroyed:
                DllCall("DestroyIcon", "uint", hIcon)
                ; Cache the icon to save memory and improve loading performance:
                IconArray%ExtID% := IconNumber
            }
        }

        ; Create the new row in the ListView and assign it the icon number determined above:
        LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, FileExt)
    }
    GuiControl, +Redraw, MyListView  ; Re-enable redrawing (it was disabled above).
    LV_ModifyCol()  ; Auto-size each column to fit its contents.
    LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
    return

    ButtonClear:
    LV_Delete()  ; Clear the ListView, but keep icon cache intact for simplicity.
    return

    ButtonSwitchView:
    if not IconView
        GuiControl, +Icon, MyListView    ; Switch to icon view.
    else
        GuiControl, +Report, MyListView  ; Switch back to details view.
    IconView := not IconView             ; Invert in preparation for next time.
    return

    MyListView:
    if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
    {
        LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
        LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
        Run %FileDir%\%FileName%,, UseErrorLevel
        if ErrorLevel
            MsgBox Could not open "%FileDir%\%FileName%".
    }
    return

    GuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
    if A_GuiControl <> MyListView  ; Display the menu only for clicks inside the ListView.
        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

    ContextOpenFile:  ; The user selected "Open" in the context menu.
    ContextProperties:  ; The user selected "Properties" in the context menu.
    ; For simplicitly, operate upon only the focused row rather than all selected rows:
    FocusedRowNumber := LV_GetNext(0, "F")  ; Find the focused row.
    if not FocusedRowNumber  ; No row is focused.
        return
    LV_GetText(FileName, FocusedRowNumber, 1) ; Get the text of the first field.
    LV_GetText(FileDir, FocusedRowNumber, 2)  ; Get the text of the second field.
    IfInString A_ThisMenuItem, Open  ; User selected "Open" from the context menu.
        Run %FileDir%\%FileName%,, UseErrorLevel
    else  ; User selected "Properties" from the context menu.
        Run Properties "%FileDir%\%FileName%",, UseErrorLevel
    if ErrorLevel
        MsgBox Could not perform requested action on "%FileDir%\%FileName%".
    return

    ContextClearRows:  ; The user selected "Clear" in the context menu.
    RowNumber = 0  ; This causes the first iteration to start the search at the top.
    Loop
    {
        ; Since deleting a row reduces the RowNumber of all other rows beneath it,
        ; subtract 1 so that the search includes the same row number that was previously
        ; found (in case adjacent rows are selected):
        RowNumber := LV_GetNext(RowNumber - 1)
        if not RowNumber  ; The above returned zero, so there are no more selected rows.
            break
        LV_Delete(RowNumber)  ; Clear the row from the ListView.
    }
    return

    GuiSize:  ; Expand or shrink the ListView in response to the user's resizing of the window.
    if A_EventInfo = 1  ; The window has been minimized.  No action needed.
        return
    ; Otherwise, the window has been resized or maximized. Resize the ListView to match.
    GuiControl, Move, MyListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - 40)
    return

    GuiClose:  ; When the window is closed, exit the script automatically:
    ExitApp