Gui +LastFound
Loop % LV_GetCount("Column")
SendMessage, 4125, A_Index - 1, 0, SysListView321 ; 4125 为 LVM_GETCOLUMNWIDTH.
MsgBox Column %A_Index%'s width is %ErrorLevel%.
返回下一个选择的,选中的或焦点行的行号。如果没有找到, 则返回零. 如果 StartingRowNumber 省略或小于 1,则从列表的顶部开始搜索。否则,从 StartingRowNumber 行后开始搜索。如果省略第二个参数, 则函数搜索下一个选择的/高亮的行. 否则, 指定 "C" 或 "Checked" 来寻找下一个选中的行; 或指定 "F" 或 "Focused" 来寻找焦点行 (在整个列表中不可能有多个焦点行, 且有时甚至没有). 下面的例子报告 ListView 中所有选择的行:
RowNumber = 0 ; 这样使得首次循环从列表的顶部开始搜索.
RowNumber := LV_GetNext(RowNumber) ; 在前一次找到的位置后继续搜索.
if not RowNumber ; 上面返回零, 所以选择的行已经都找到了.
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 为 LVM_GETITEMSTATE. 0xF000 为 LVIS_STATEIMAGEMASK.
IsChecked := (ErrorLevel >> 12) - 1 ; 如果 RowNumber 为选中的则设置 IsChecked 为真, 否则为假.
获取在指定的 RowNumber 和 ColumnNumber 位置上的文本并保存到 OutputVar。如果省略 ColumnNumber,则它默认为 1(首列的文本)。如果 RowNumber 为 0,则获取列标题的文本。如果文本长度超过 8191, 则仅获取前 8191 个字符. 此函数成功时返回 1 而失败时返回 0. 失败时,OutputVar 也被置空。
用户可能已经完成的拖放操作不会修改脚本看到的列编号. 例如, 最初首列的编号仍是 1, 即使用户已经把它拖到其他列的右边.
G 标签通知 (主要)
g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户在控件中执行动作时 MySubroutine 标签会自动运行. 此子程序中可引用内置变量 A_Gui 和 A_GuiControl 来找出产生事件的是哪个窗口和 ListView. 更重要的是, 它可以参考 A_GuiEvent, 其包含下列字符串或字母的其中一个 (考虑到和未来版本的兼容性, 脚本不应假定这些字符串或字母是唯一可能的值):
DoubleClick:用户在控件内双击了。变量 A_EventInfo 包含焦点行号. LV_GetNext() 可用来获取首个选中的行号,当用户在空位置双击时为 0。
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 包含焦点行号. 在 v1.0.44+, 即使不含 AltSubmit 此通知也会产生.
d (小写的 D): 和上面相同, 除了指右键拖动而不是左键.
e(小写的 E):用户完成编辑一行的首个字段(只有当 ListView 选项中含有 -ReadOnly 时用户才可以进行编辑)。变量 A_EventInfo 包含目标行号.
G 标签通知 (次要)
如果 ListView 的 选项 中含有单词 AltSubmit, 则其 g 标签会运行的更频繁并且 A_GuiEvent 还可能包含下列值:
Normal: 用户左键单击了一行. 变量 A_EventInfo 包含焦点行号.
RightClick: 用户右键单击了一行. 变量 A_EventInfo 包含焦点行号. 在大多数情况下, 最好不要通过显示菜单来响应此通过. 而应使用 GuiContextMenu 标签, 因为它还能识别 Appskey. 例如:
GuiContextMenu: ; 运行此标签来响应右键点击或按下 Appskey.
if A_GuiControl <> MyListView ; 这个检查是可选的. 让它只为 ListView 中的点击显示菜单.
return
; 在提供的坐标处显示菜单, A_GuiX 和 A_GuiY. 应该使用这些
; 因为即使用户按下 Appskey 它们也会提供正确的坐标:
Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
return
A: 激活了一行, 这种情况默认发生在双击这行的时候. 变量 A_EventInfo 包含目标行号.
C: ListView 释放了鼠标捕获.
E:用户开始编辑一行的首个字段(只有在 ListView 选项中含有 -ReadOnly 时用户才可以进行编辑)。变量 A_EventInfo 包含目标行号.
F: ListView 接收到键盘焦点.
f (小写的 F): ListView 失去了键盘焦点.
I: 项目发生了变化. 通过变成选择的/未选择的, 选中的/未选中的等让一行改变了. 如果用户选择了一个新行, 则至少会接收到两个这样的通知: 一个是在取消之前的行时, 而另一个是在选择新行时. 在 v1.0.44+, 变量 A_EventInfo 包含目标行号. 在 v1.0.46.10+, ErrorLevel 包含零个或多个下列字母来表示项目发生的变化: S (选择) 或 s (取消选择), 和/或 F (成为焦点) 或 f (失去焦点), 和/或 C (选中) 或 c (取消选中). 例如, SF 表示此行被选择且成为了焦点. 要检查是否存在一个特定的字母,请使用解析循环或带区分大小写选项的 InStr(); 例如:InStr(ErrorLevel, "S", true)。注: 考虑到和未来版本的兼容性, 脚本不应假定 "SsFfCc" 包含了所有可能的字母或字母组合. 此外, 指定 Critical 作为 g 标签 子程序的首行来确保接收到所有的 "I" 通知 (否则, 如果脚本无法跟上, 则它们其中一些可能会丢失).
K: 当 ListView 拥有焦点时用户按下了一个键. A_EventInfo 包含此键的虚拟按键代码, 这是介于 1 和 255 之间的数字. 如果此键是字母键,则在大多数键盘布局中可以使用 Chr(A_EventInfo) 把它转换成相应的字符。不论 WantF2 选项如何都可以接收到 F2 键击。然而,不会接收到 Enter 键击;要接收它,请像下面描述的那样使用一个默认按钮。
M: 选取框. 用户开始在一组行或图标周围拖动一个矩形选区.
S: 用户开始滚动 ListView.
s (小写的 S): 用户完成滚动 ListView.
图像列表 (把图标添加到 ListView 的方法)
图像列表是保存在内存中的一组大小相同的图标. 创建时每个图像列表是空的. 脚本重复调用 IL_Add() 来添加图标到列表中, 且给每个图标分配一个序号, 序号从 1 开始. 脚本引用此编号在一行中或列标题中显示一个特定的图标. 这是个可运行示例, 其中演示了如何在 ListView 的行中显示图标:
Gui, Add, ListView, h200 w180, Icon & Number|Description ; 创建 ListView.
ImageListID := IL_Create(10) ; 创建加载 10 个小图标的图像列表.
LV_SetImageList(ImageListID) ; 把上面的图像列表指定给当前的 ListView.
Loop 10 ; 把 DLL 中的一系列图标装入图像列表.
IL_Add(ImageListID, "shell32.dll", A_Index) ; 省略 DLL 的路径, 这样它也适用于 Windows 9x.
Loop 10 ; 在 ListView 中添加行 (出于演示的目标, 每个图标一行).
LV_Add("Icon" . A_Index, A_Index, "n/a")
LV_ModifyCol("Hdr") ; 自动调整列宽.
Gui Show
return
GuiClose: ; 当用户关闭 ListView 所在的 GUI 窗口时退出脚本.
ExitApp
创建新的初始为空的图像列表,并返回图像列表的唯一 ID(失败时为 0)。InitialCount 为希望马上放入列表的图标数(如果省略,则它默认为 2)。GrowCount 为列表每次将增长时超出当前列表容量的图标数(如果省略,则它默认为 5)。LargeIcons 应该为数值:如果不为零,则图像列表将包含大图标。如果为零, 则它包含小图标 (这是省略时的默认情况). 会按比例对添加到列表中的图标自动进行缩放以符合系统中大图标和小图标的尺寸.
此函数一般在 ListView 添加行之前调用。它设置关联的图像列表,其中的图标会显示在 ListView 的行中(可选的,以及列)。ImageListID 为前面调用 IL_Create() 返回的数字。如果省略第二个参数, 则自动检测图像列表中的图标为大图标还是小图标. 否则,对于大图标指定 0,对于小图标指定 1,而状态图标则为 2(还没有直接支持状态图标,不过可以通过 SendMessage 使用)。
一个 ListView 最多可以关联两个图像列表: 小图标和/或大图标. 这可用于脚本允许用户在大图标视图和其他视之间切换的时候. 要再关联一个图像列表到 ListView, 请再次调用 LV_SetImageList(), 其中指定第二个列表的 ImageListID. 同时关联有大图标和小图标图像列表的 ListView 应该确保两个列表中包含图标的顺序相同. 这是因为使用一个指定图标的大小版本时会引用相同的 ID 编号.
尽管除了图标模式和平铺模式显示小图标外, 对于其他的 视图模式 这是惯例, 但通过传递一个大图标列表到 LV_SetImageList 并且在第二个参数中指定 1 (小图标) 可以覆盖此行为. 这也增加了 ListView 中每行的高度以适合大图标.
如果成功, 则 LV_SetImageList() 返回之前与 ListView 关联的 ImageListID (如果没有则为 0). 任何分离的图像列表一般应使用 IL_Destroy(ImageListID) 进行销毁.
添加图标或图片到指定的 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. 比 XP 早的操作系统可以通过复制微软免费的 GDI+ DLL 到 AutoHotkey.exe 文件夹中来提供支持 (但如果是 已编译脚本, 则复制此 DLL 到脚本的文件夹). 要下载这个 DLL, 请在 www.microsoft.com 搜索下列短语: gdi redistributable
删除指定的图像列表,成功时返回 1 而失败返回 0。通常没必要销毁图像列表, 因为一旦关联到 ListView, 当 ListView 或其父窗口销毁时它们会被自动销毁. 但是,如果一个 ListView 和其他 ListView 共享图像列表(通过在选项中包含 0x40),在所有使用此图像列表的 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 和 Shlwapi.dll (它们随各种更新和应用程序例如 Internet Explorer 3.0 或更高版本一起发布), 则 ListView 的功能受到更多限制且某些特性可能和预期不同.
TreeView, 其他控件类型, Gui, GuiContextMenu, GuiControl, GuiControlGet, ListView 样式表
; 指定行号为 0 来选择或取消选择所有行:
LV_Modify(0, "Select") ; 选择所有.
LV_Modify(0, "-Select") ; 取消选择所有.
LV_Modify(0, "-Check") ; 取消选中所有 复选框.
; 自动根据内容调整所有列的宽度:
LV_ModifyCol() ; 此时不需要参数.
; 主示例
; 下面是一个比此页面顶部附近那个更精巧的可运行脚本.
; 它显示用户文件夹中的文件, 且每个文件分配一个与其类型关联的图标.
; 用户在一个文件上双击或在一个或多个文件上右击后, 会显示上下文菜单.
; 允许用户最大化窗口或拖动来改变窗口的大小:
Gui +Resize
; 创建一些按钮:
Gui, Add, Button, Default gButtonLoadFolder, Load a folder
Gui, Add, Button, x+20 gButtonClear, Clear List
Gui, Add, Button, x+20, Switch View
; 创建 ListView 及其列:
Gui, Add, ListView, xm r20 w700 vMyListView gMyListView, Name|In Folder|Size (KB)|Type
LV_ModifyCol(3, "Integer") ; 为了排序, 表示 Size 列中的内容是整数.
; 创建图像列表, 这样 ListView 才可以显示图标:
ImageListID1 := IL_Create(10)
ImageListID2 := IL_Create(10, 10, true) ; 大图标列表和小图标列表.
; 关联图像列表到 ListView, 然而它就可以显示图标了:
LV_SetImageList(ImageListID1)
LV_SetImageList(ImageListID2)
; 创建作为上下文菜单的弹出菜单:
Menu, MyContextMenu, Add, Open, ContextOpenFile
Menu, MyContextMenu, Add, Properties, ContextProperties
Menu, MyContextMenu, Add, Clear from ListView, ContextClearRows
Menu, MyContextMenu, Default, Open ; 让 "Open" 粗体显示表示双击时会执行相同的操作.
; 显示窗口并返回. 当用户执行预期的动作时
; 操作系统会通知脚本:
Gui, Show
return
ButtonLoadFolder:
Gui +OwnDialogs ; 强制用户解除此对话框后才可以操作主窗口.
FileSelectFolder, Folder,, 3, Select a folder to read:
if not Folder ; 用户取消了对话框.
return
; 检查文件夹名称的最后一个字符是否为反斜线, 对于根目录则会如此,
; 例如 C:\. 如果是, 则移除这个反斜线以避免之后出现两个反斜线.
StringRight, LastChar, Folder, 1
if LastChar = \
StringTrimRight, Folder, Folder, 1 ; 移除尾随的反斜线.
; 计算 SHFILEINFO 结构需要的缓存大小.
sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
VarSetCapacity(sfi, sfi_size)
; 获取所选择文件夹中的文件名列表并添加到 ListView:
GuiControl, -Redraw, MyListView ; 在加载时禁用重绘来提升性能.
Loop %Folder%\*.*
FileName := A_LoopFileFullPath ; 必须保存到可写的变量中供后面使用.
; 建立唯一的扩展 ID 以避免变量名中的非法字符,
; 例如破折号. 这种使用唯一 ID 的方法也会执行地更好,
; 因为在数组中查找项目不需要进行搜索循环.
SplitPath, FileName,,, FileExt ; 获取文件扩展名.
if FileExt in EXE,ICO,ANI,CUR
ExtID := FileExt ; 特殊 ID 作为占位符.
IconNumber = 0 ; 进行标记这样每种类型就含有唯一的图标.
else ; 其他的扩展名/文件类型, 计算它们的唯一 ID.
ExtID = 0 ; 进行初始化来处理比其他更短的扩展名.
Loop 7 ; 限制扩展名为 7 个字符, 这样之后计算的结果才能存放到 64 位值.
StringMid, ExtChar, FileExt, A_Index, 1
if not ExtChar ; 没有更多字符了.
break
; 把每个字符与不同的位位置进行运算来得到唯一 ID:
ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
; 检查此文件扩展名的图标是否已经在图像列表中. 如果是,
; 可以避免多次调用并极大提高性能,
; 尤其对于包含数以百计文件的文件夹而言:
IconNumber := IconArray%ExtID%
if not IconNumber ; 此扩展名还没有相应的图标, 所以进行加载.
; 获取与此文件扩展名关联的高质量小图标:
if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", FileName
, "uint", 0, "ptr", &sfi, "uint", sfi_size, "uint", 0x101) ; 0x101 为 SHGFI_ICON+SHGFI_SMALLICON
IconNumber = 9999999 ; 把它设置到范围外来显示空图标.
else ; 成功加载图标.
; 从结构中提取 hIcon 成员:
hIcon := NumGet(sfi, 0)
; 直接添加 HICON 到小图标和大图标列表.
; 下面加上 1 来把返回的索引从基于零转换到基于一:
IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", ImageListID1, "int", -1, "ptr", hIcon) + 1
DllCall("ImageList_ReplaceIcon", "ptr", ImageListID2, "int", -1, "ptr", hIcon)
; 现在已经把它复制到图像列表, 所以应销毁原来的:
DllCall("DestroyIcon", "ptr", hIcon)
; 缓存图标来节省内存并提升加载性能:
IconArray%ExtID% := IconNumber
; 在 ListView 中创建新行并把它和上面的图标编号进行关联:
LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, FileExt)
GuiControl, +Redraw, MyListView ; 重新启用重绘 (上面把它禁用了).
LV_ModifyCol() ; 根据内容自动调整每列的大小.
LV_ModifyCol(3, 60) ; 把 Size 列加宽一些以便显示出它的标题.
return
ButtonClear:
LV_Delete() ; 清理 ListView, 但为了简化保留了图标缓存.
return
ButtonSwitchView:
if not IconView
GuiControl, +Icon, MyListView ; 切换到图标视图.
GuiControl, +Report, MyListView ; 切换回详细信息视图.
IconView := not IconView ; 进行反转以为下次做准备.
return
MyListView:
if A_GuiEvent = DoubleClick ; 脚本还可以检查许多其他的可能值.
LV_GetText(FileName, A_EventInfo, 1) ; 从首个字段中获取文本.
LV_GetText(FileDir, A_EventInfo, 2) ; 从第二个字段中获取文本.
Run %FileDir%\%FileName%,, UseErrorLevel
if ErrorLevel
MsgBox Could not open "%FileDir%\%FileName%".
return
GuiContextMenu: ; 运行此标签来响应右键点击或按下 Appskey.
if A_GuiControl <> MyListView ; 仅在 ListView 中点击时才显示菜单.
return
; 在提供的坐标处显示菜单, A_GuiX 和 A_GuiY. 应该使用这些
; 因为即使用户按下 Appskey 它们也会提供正确的坐标:
Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
return
ContextOpenFile: ; 用户在上下文菜单中选择了 "Open".
ContextProperties: ; 用户在上下文菜单中选择了 "Properties".
; 为了简化, 仅对焦点行进行操作而不是所有选择的行:
FocusedRowNumber := LV_GetNext(0, "F") ; 查找焦点行.
if not FocusedRowNumber ; 没有焦点行.
return
LV_GetText(FileName, FocusedRowNumber, 1) ; 获取首个字段的文本.
LV_GetText(FileDir, FocusedRowNumber, 2) ; 获取第二个字段的文本.
IfInString A_ThisMenuItem, Open ; 用户在上下文菜单中选择了 "Open".
Run %FileDir%\%FileName%,, UseErrorLevel
else ; 用户在上下文菜单中选择了 "Properties".
Run Properties "%FileDir%\%FileName%",, UseErrorLevel
if ErrorLevel
MsgBox Could not perform requested action on "%FileDir%\%FileName%".
return
ContextClearRows: ; 用户在上下文菜单中选择了 "Clear".
RowNumber = 0 ; 这会使得首次循环从顶部开始搜索.
; 由于删除了一行使得此行下面的所有行的行号都减小了,
; 所以把行号减 1, 这样搜索里包含的行号才会与之前找到的行号相一致
; (以防选择了相邻行):
RowNumber := LV_GetNext(RowNumber - 1)
if not RowNumber ; 上面返回零, 所以没有更多选择的行了.
break
LV_Delete(RowNumber) ; 从 ListView 中删除行.
return
GuiSize: ; 扩大或缩小 ListView 来响应用户对窗口大小的改变.
if A_EventInfo = 1 ; 窗口被最小化了. 无需进行操作.
return
; 否则, 窗口的大小被调整过或被最大化了. 调整 ListView 的大小来适应.
GuiControl, Move, MyListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - 40)
return