Gui,Add,ListView

GUIウィンドウにリストビューコントロールを追加する。列や項目の操作を行う組み込み関数も用意されている。

Gui, Add, ListView [, Options, ColumnTitles]

Parameters

引数名説明
Options オプションを半角スペース区切りで列挙。
共通のオプションについては、Gui,Addの項参照。
固有のオプションは後述。
「V」オプションで変数を関連付けても、変数に情報が格納されることはない。ただし、GuiControlなどのコマンドでコントロールを指定するために利用できる。
Gでラベル名を指定すると、各種の操作が行われるごとにサブルーチンが実行される。詳しくはイベントの節を参照。
ColumnTitles 詳細表示の列の見出しを「|」で区切って列挙する。(例:「名前|サイズ|更新日時」)
Gui,+Delimiter`n」のようにすると、区切り文字を「|」以外のもの(この例では改行)に変更できる。
各列の幅の初期状態は、テキストが収まる幅になる。

固有のOption

Report
表示スタイルを詳細表示にする。
デフォルトであり、Gui,Addでは使用しない。
ほかのスタイルから変更したいときに「GuiControl,+Report,List」などとして使う。
Icon
表示スタイルを大きいアイコン表示にする。
IconSmall
表示スタイルを小さいアイコン表示にする
Tile
表示スタイルを大きい一覧表示にする(XP以降のみ有効)
List
表示スタイルを一覧表示にする
AltSubmit
「G」オプションで指定されたサブルーチンが呼び出されるイベントの数を拡張する。
詳細は後述。
cCOLOR
COLORに文字色を指定する。(例:「cFF9900」「cRed」「cDefault」)
RRGGBB形式のカラーコードや色名、「Default」を指定できる。
BackgroundCOLOR
COLORに背景色を指定する。(例:「BackgroundFF9900」「BackgroundRed」「BackgroundDefault」)
RRGGBB形式のカラーコードや色名、「Default」を指定できる。
このオプションがない場合、Gui,Colorの指定に依存する。
Checked
リスト項目にチェックボックスをつける。
CountROWS
ROWSに予測される項目数を指定する(例:「Count1000」)
項目が追加される際、この数値にしたがってまとめてメモリを確保する。
少なすぎると大量の項目を追加する際に時間がかかってしまうが、多くしすぎるとメモリ消費が無駄に増える。
Grid
詳細表示時に行・列を区切る線を表示する
Hdr
詳細表示時に列の見出しを表示する。
デフォルトで有効になっている。
「-Hdr」で見出しを非表示にできる。
LVXXXXXXXX
リストビューの拡張スタイル(LVS_EX_*)を設定する。 XXXXXXXXに拡張スタイルの番号を指定する。(例:「LV0x100」=LVS_EX_FLATSB)
LV0x10
詳細表示時に列見出しの部分をドラッグして列を入れ替えることを可能にする。
デフォルトで有効になっている。
「-LV0x10」で列入れ替え禁止にできる。
列を入れ替えても、リストビュー操作関数などで扱う列番号は変わらない。
LV0x20
詳細表示時に、行のどこをクリックしても項目を選択できる行選択にする。
デフォルトで有効になっている。
「-LV0x20」で1列目のテキストをクリックしないと選択できなくする。
Multi
複数選択を可能にする。
デフォルトで有効になっている。
「-Multi」でひとつしか選択できなくできる。
NoSortHdr
列の見出しをクリックして、その列の内容で並び替える機能を無効にする。
見出し部分は平坦な表示になり、クリックしても「G」オプションで指定したサブルーチンは呼び出されなくなる。
このオプションは、GuiControlコマンドで後から変更することはできない。
NoSort
列の見出しをクリックして、その列の内容で並び替える機能を無効にする。
見出し部分の表示はそのままで、クリックされると「G」オプションで指定したサブルーチンが呼び出される。
ReadOnly
テキストを変更禁止にする。
デフォルトで有効になっている。
「-ReadOnly」とすると、1列目の部分をクリックしたりF2キーを押すことで内容を編集することができるようになる。
編集が行われると、「G」オプションで指定したサブルーチンが呼び出される。
WantF2
「-ReadOnly」が設定されているとき、F2キーでテキストを編集できるようにする。
デフォルトで有効になっている。
「-WantF2」とすると、F2キーが押されても編集状態にならないようにできる。
Rn
nに行数を数値で指定する(例:「R10」)
コントロールの高さは、この行数が収まる高さになる。
Icon表示にした場合などは、項目が縦にこの数だけ収まるような高さになる。
Sort
項目が追加されるとき1列目の内容で自動的に昇順ソートされるようにする。
明示的にほかの列でソートを行うと、並び順がおかしくなる。
SortDesc
項目が追加されるとき1列目の内容で自動的に降順ソートされるようにする。
明示的にほかの列でソートを行うと、並び順がおかしくなる。

ListView操作用組み込み関数

リストビューを操作するために、多数の機能が関数として用意されている。
LV系の関数が操作対象とするリストビューは、デフォルトGUIウィンドウ上のカレントリストビューである。
カレントリストビューは、通常は最後に項目を追加したリストビューだが、「Gui,ListView,LVName」のようにして変更できる。
GUIウィンドウが存在しなかったり、デフォルトGUIウィンドウ上にリストビューコントロールが存在しなかった場合、LV系関数は「0」を返す。

これらの関数で使用される「項目番号」は、一番上が「1」になる。

イメージリスト

リストなどに表示するアイコンは、イメージリストに登録しておく。
IL_Createでイメージリストを作成し、LV_SetImageListでリストビューに割り当てる必要がある。
大きいアイコンと小さいアイコンは別々のイメージリストに保持する。

IL_Create([InitialCount, GrowCount, IsLargeIcons])
イメージリストを新規作成する。
InitialCountで最初にメモリを確保しておくアイコンの数を、GrowCountでメモリを確保してあるアイコン数を超えたときに新たに確保する数を指定できる。デフォルトはそれぞれ2と5である。
IsLargeIconsを「1」にすると、小さいアイコンではなく大きいアイコンを保持するイメージリストを作成する。
作成に成功すると、固有の番号が割り当てられ、その番号が返される。ほかの関数でImageListID引数に使用するので、必ず変数に代入しておく必要がある。作成に失敗した場合は0が返される。
LV_SetImageList(ImageListID [,Type])
リストビューにImageListIDで指定したイメージリストを割り当てる。
Typeに「0」を指定すると大きいアイコンに、「1」を指定すると小さいアイコンに割り当てられる。また、「2」を指定すると状態アイコンに割り当てられるが、状態アイコンに関する関数は今のところ用意されていない。
Typeを省略した場合は、IL_CreateのIsLargeIconsでの指定に従い大きいアイコンか小さいアイコンに割り当てられる。
返り値はそれまでリストビューに割り当てられていたイメージリストのIDになる。(なければ「0」)
IL_Add(ImageListID, Filename [, IconNumber, ResizeNonIcon])
ImageListIDで指定したイメージリストにFilenameで指定したファイルを追加する。
追加できるファイルタイプは、ICO/CUR/ANI/EXE/DLL/BMP/GIF/JPG/PNG/TIF/EXIF/WMF/EMFである。
EXE/DLLでは、IconNumberにアイコングループの番号を指定する。省略時は1番目になる。
BMP/GIF/JPG/PNG/TIF/EXIF/WMF/EMFの画像ファイルでは、IconNumberに透過色に指定する色を16進数で指定する(例:「0xFFCC99」)。
PNGなどの透過色・アルファチャンネル情報を含むファイルでは指定する必要はない。
ResizeNonIconを1にすると、画像をアイコンのサイズにリサイズする。省略時や「0」にした場合は、画像の左上からアイコンのサイズぶんだけが切り出される。
追加に成功すると、アイコンを指定するときに使うアイコン番号が返される。失敗時は「0」が返される。
IL_Destroy(ImageListID)
ImageListIDで指定したイメージリストを破棄する。

列操作

LV_ModifyCol([ColumnNumber, Options, ColumnTitle])
ColmnNumber番目の列のオプションをOptionsに、見出しテキストをColmunTitleに変更する。
Optionsには後述のオプションを半角スペースもしくはTab文字で区切って文字列として与える。
ColmunTitleを省略すると、オプションだけが変更される。
ColumunNumberだけを指定すると、その列の幅をすべての項目のテキストが表示しきれるように調節する。
すべての引数を省略すると、すべての列の幅を調節する。
失敗すると「0」が、成功すると「1」が返る。
LV_InsertCol(ColumnNumber [, Options, ColumnTitle])
新しい列をColumnNumber番目に挿入する。
ColumnNumberが存在する列数よりも大きかった場合、一番最後に追加される。
Optionsには後述のオプションを、ColumnTitleには列の見出しを指定する。
新しく追加された列は、各項目のテキストは空になる。
ただし、ColumnNumberが1の場合は、前の1列目の内容が継承され、もともと1列目だった列が空になる。
失敗すると「0」が、成功すると追加された列の番号が返る。
LV_DeleteCol(ColumnNumber)
ColumnNumber番目の列を削除する。
以降、ColumnNumber番目以降の列の列番号はひとつずつ前にずらされる。
失敗すると「0」が、成功すると「1」が返る。
WindowsXP未満のOSでは、1番目の列は削除できない。

列操作で使用されるオプション

LV_ModifyCol、LV_InsertColのOptions引数に指定できるオプションには以下のものがある。

整数値
「100」など整数値を指定すると、その列の幅を設定できる。
Integer
その列でソートするときに、文字列としてではなく整数値としてソートする。
文字列の場合、「100」は「12」より小さくなってしまう。
先頭に数字列が付いている文字列は、その数字列の数値として扱われるが、先頭が数字でない文字列は「0」として扱われる。
扱える数値の範囲は-2147483648から2147483647までである。
Float
その列をソートするとき、小数値としてソートする。
Text
その列をソートするとき、文字列としてソートする。
デフォルトでこの状態である。
Uni
列見出しを2回クリックして逆順にソートすることを禁止する。
-Uni
「-Uni」の指定を解除する
Desc
昇順ソートではなく降順ソートにする。
Uniが指定されていない場合、2回見出しをクリックすれば昇順ソートになる。
-Desc
「-Desc」の指定を解除する
Case
ソート方法がTextのとき、大文字小文字を区別する。
-Case
「-Case」の指定を解除する
-CaseLocale
現在のユーザーのロケール設定に沿って大文字小文字の違いを無視する。
日本語環境の場合、全角のアルファベットなども対象となる。
Logical
ソートの際、文字列の途中に含まれている数字列も数値として比較する。
NoSort
列の見出しをクリックして、その列の内容で並び替える機能を無効にする。
見出し部分の表示はそのままで、クリックされると「G」オプションで指定したサブルーチンが呼び出される。
-NoSort
「-NoSort」の指定を解除する
Sort
その列で昇順ソートさせる。
後でほかの列見出しがクリックされれば、その列でソートされる。
SortDesc
その列で降順ソートさせる。
後でほかの列見出しがクリックされれば、その列でソートされる。
Right
テキストを右そろえにする。
IntegerやFloatを指定すると、デフォルトでこの状態になる。
Center
テキストを中央そろえにする。
Left
テキストを左そろえにする。
IntegerやFloatが指定されていない場合のデフォルトはこの状態である。
Auto
その列の幅をすべての項目のテキストが表示しきれるように調節する。
AutoHdr
その列の幅を列の見出しとすべての項目のテキストが表示しきれるように調節する。
最後の列でこれを指定した場合、リストビューの右端まで列が広げられる。
IconN
列の見出しにアイコンを表示する。
Nにアイコン番号を指定する。
IconRight
IconNでアイコンを表示するとき、左ではなく右に表示する。
-Icon
列見出しにアイコンを表示しなくする

項目操作

LV_Add([Options, Col1, ...ColN])
リストの最後に項目を追加する。
Optionsには後述のオプションを半角スペースもしくはTab文字で区切って文字列として与える。
Col1...ColNには、各列に表示するテキストを文字列もしくは数値で指定する。
Col1...ColNに空文字列が指定された場合や省略された場合は、表示は空になる。
追加に成功すれば、追加された項目の項目番号が返される。追加に失敗した場合は、「0」が返される。
LV_Insert(RowNumber [, Options, Col1, ...ColN])
RowNumberで指定した位置に項目を挿入する。
それ以外の引数はLV_Addと同じ。
現在の項目数よりも大きい値を指定した場合は、一番最後に挿入される。
追加に成功すれば、追加された項目の項目番号が返される。追加に失敗した場合は、「0」が返される。
LV_Modify(RowNumber, Options [, Col1, ...ColN])
RowNumberで指定した項目のオプションや列テキストを変更する。
RowNumberに「0」を指定すると、すべての項目のオプションをまとめて変更できる。
Col1...ColNに空文字列が指定された場合や省略された場合は、その列のテキストは変更されない。
変更に失敗した項目があると「0」が、すべて成功すると「1」が返る。
LV_Delete([RowNumber])
RowNumberで指定した項目を削除する。
RowNumberを省略した場合、すべての項目が削除される。
削除に失敗すると「0」が、成功すると「1」が返る。

項目操作で使用されるオプション

項目操作系の関数のOptions引数に指定できるオプションには以下のものがある。

Vis
スクロールバーが表示されている状態で、当該項目が画面外にあるとき、当該項目が表示されるようにスクロールさせる。
LV_Modify()関数でのみ有効。
Select
Select1
項目を選択状態にする。
-Select
Select0
項目を非選択状態にする。
Focus
Focus1
キーボードフォーカスをその項目にあわせる
-Focus
Focus0
キーボードフォーカスがその項目に合わさっていない状態にする
Check
Check1
チェックボックスのチェックをOnにする。
-Check
Check0
チェックボックスのチェックをOffにする。
IconN
Nにアイコン番号を指定する。(例:「Icon1」)
後述のイメージリスト操作関数でイメージリストに登録した番号を指定する。
このオプションが指定されなかった場合は、イメージリストの最初のアイコンが使用される。
「Icon1000」など、イメージリストに登録されている数よりも大きな値を指定すると、空白が表示される。
イメージリストにアイコンが登録されてないと、何も表示されずアイコンを表示するはずの領域は詰められる。
ColN
Nに列番号を指定する。1列目は「1」である。(例:「Col2」)
引数のCol1...ColNで対象となる列の開始位置を変更する。
たとえば、「LV_Modify(1,"Col2","aaa","bbb"」とすると、1つめの項目の2列目を「aaa」、3列目を「bbb」に変更する。

情報取得

LV_GetCount([Type])
リストビューの項目数を返す。
Typeに「"S"」を指定すると、選択項目の数が返される。
Typeに「"Col"」を指定すると、列の数を返す。
LV_GetNext([StartingRowNumber, [Type])
StartingRowNumber番目以降の項目で最初の選択されている項目の項目番号を返す。
StartingRowNumberが省略された場合は、一番上の選択されている項目を返す。
Typeに「C」を指定すると、チェックされている項目の番号を返す。
Typeに「F」を指定すると、フォーカスがある項目の番号を返す(なお、フォーカスはひとつしかない)。
該当項目がない場合は「0」を返す。
LV_GetText(OutputVar, RowNumber [, ColumnNumber])
RowNumber番目の項目のColumnNumber列目のテキストを取得しOutputVarに格納する。
ColumnNumberが省略された場合、1番目の列のテキストが取得される。
RowNumberを「0」にすると、列の見出しのテキストが取得される。
テキストが8191バイト以上ある場合は、最初の8191バイトだけが取得される。
失敗すると「0」が、成功すると「1」が返る。

イベント

「G」オプションでラベル名を指定していると、下記のイベントが発生するたびにサブルーチンが実行される。
このとき、A_GuiEvent変数にイベント名が格納される。
「E」と「e」など大文字と小文字と小文字の違うイベント名は別物である。 なお、イベントは今後も追加される可能性がある。

DoubleClick
項目がダブルクリックされた。
A_EventInfo変数にはダブルクリックされた項目の項目番号が格納される。
項目以外の部分がクリックされた場合は、フォーカスのある項目の番号が格納される。
R
項目が右クリックでダブルクリックされた。
A_EventInfo変数にはフォーカスのある項目の項目番号が格納される。
ColClick
列見出しのボタンがクリックされた。
A_EventInfo変数には列番号が格納される。
列番号は、ユーザーがドラッグ&ドロップで列の順番を入れ替えても変わらない。最初に1列目立った列は、2列目に移動されても列番号は1のままである。
「NoSort」オプションで見出しクリックによるソートを無効にして、自前でソートを行いたいときなどに使用する。
e
「-ReadOnly」で1列目のテキストを編集可能にしてあるとき、テキストを編集し終わったときに実行される。
A_EventInfo変数には編集された行の番号が格納される。
D
項目をドラッグ開始したときに実行される。
今のところ、項目のドラッグ&ドロップに関する機能は用意されていない。
A_EventInfo変数にはフォーカスのある項目の項目番号が格納される。
d
項目を右クリックでドラッグ開始したときに実行される。
今のところ、項目のドラッグ&ドロップに関する機能は用意されていない。
A_EventInfo変数にはフォーカスのある項目の項目番号が格納される。

拡張イベント

AltSubmitオプションを指定すると、上記のイベントに加え、下記のイベント時にもサブルーチンが呼び出される。

Normal
項目が左クリックされた。
A_EventInfo変数にはフォーカスのある項目の項目番号(フォーカスがなければ「0」)が格納される。
RightClick
項目が右クリックされた。
項目が右クリックでダブルクリックされた。
A_EventInfo変数にはフォーカスのある項目の項目番号が格納される。
Appsキーなどの代替コンテキストメニュー呼び出し操作では実行されない。
A
項目がアクティブ化された。
通常はDoubleClickイベントの後に発生する。
A_EventInfo変数にはアクティブ化された項目の項目番号が格納される。
C
マウスボタンが押し下げられたり離されたときに発生する。
E
「-ReadOnly」で1列目のテキストを編集可能にしてあるとき、テキストを編集し始めたときに実行される。
A_EventInfo変数には編集される行の番号が格納される。
F
リストビューコントロールがフォーカスを受け取ったときに実行される。
f
リストビューコントロールがフォーカスを失ったときに実行される。
I
リストビューの選択状態が変化したときに実行される。
A_EventInfo変数には状態が変化した行の番号が格納される。
このイベントが呼び出されたとき、ErrorLevelは以下の文字を連結した物になる。
InStr(ErrorLevel, "S", true)のようにして、どの変化が起こったかを判別できる。
S
選択された
s
選択解除された
F
フォーカスを受け取った
f
フォーカスを失った
C
チェックされた
c
チェックが外された
選択行が変ったときには、選択解除イベントと新しい行の選択イベントが別個に発生する。
K
リストビューにフォーカスがあるときにキーボードのキーが押された。
A_EventInfo変数には、押されたキーの仮想キーコードが格納される。
キーを押しっぱなしにすると、キーリピートが働きイベントが繰り返し発生する。
M
マウスによる範囲選択を開始した。
この後、選択状態が変化するたびに「I」イベントが発生し、マウスが話されると「C」イベントが発生する。
S
スクロールバーでのスクロールを開始したときに実行される。
s
スクロールバーでのスクロールを終了したときに実行される。

これらのイベントの動作を確かめるには、以下のサンプルスクリプトを利用するとよい。

Gui,Add,ListView,h600 -ReadOnly AltSubmit gLV R10,A_GuiEvent|A_EventInfo|日時
Gui,Add,Button,gClear,&Clear

Gui,Show
return

LV:
FormatTime,t,%A_Now%,yyyy/MM/dd hh:mm:ss
Lv_Add("",A_GuiEvent,A_EventInfo,t)
return

Clear:
Lv_Delete()
return

Remarks

項目の各列に表示可能なテキストの上限は260バイトである。
LV_GetTextで取得できるのは8191バイトまでである。
実際に格納できるテキスト長には上限はない。

列見出しのクリックや「LV_ModifyCol(1, "Sort") 」のような関数によるソートは、その時点でソートされるのみで、後から追加される項目には影響しない。
ListViewコントロールのオプションの「Sort」と「SortDesc」は、項目が追加されるときに動作する。
ただし、すでに存在する項目はソートされないので、あらかじめ項目がソートされていないと正しい位置に挿入されない。

リストビューにフォーカスがあるときにキーボードで文字列を入力したり、IMEで変換文字列を確定させると、1列目のテキストがその内容で始まる項目にフォーカスが移動する。

リストビューコントロールでは、Shift+クリックで最終選択位置からクリック位置までを選択、Shift+矢印キーで範囲選択、Ctrl+矢印キーの上下でフォーカスだけを移動、Ctrl+Spaceでフォーカスのある項目の選択状態を反転できる。

リストビューコントロールはEnterキーが押されたことを知ることができない。
Enterキーが押されたときに特定の動作をさせたいときは、下記の例のようにウィンドウにデフォルトボタンを設定する。
デフォルトボタンは非表示にすることも可能である。

Gui,Add,ListView,gLVEvent,col1|col2
Gui,Add,Button,gOnEnter Hidden Default
;その他の初期化動作
return

OnEnter:
	GuiControlGet, FocusedControl, Focus
	if FocusedControl = SysListView321
		Selected(LV_GetNext(1,"F"))
return

LVEvent:
	if A_GuiEvent = DoubleClick
		Selected(A_EventInfo)
return

Selected(row)
{
	;項目決定時の動作
}

Related

GUI, Gui,Add

; 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 row's first-column text.
	MsgBox You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return

GuiClose:  ; Indicate that the script should exit automatically when the window is closed.
ExitApp
; 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.

; 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)

; Gather a list of file names from the selected folder and append them to the ListView:
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 = EXE
	{
		ExtID = EXE  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that EXEs can each have a unique icon.
	}
	else  ; Non-EXE, so calculate this extension's unique ID.
	{
		ExtID = 0  ; Initializize 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 icon associated with this file extension:
		hIcon := DllCall("Shell32\ExtractAssociatedIconA", UInt, 0, Str, FileName, UShortP, iIndex)
		if not hIcon  ; Failed to load/find icon.
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else
		{
			; 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)
}
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:  ; Allows the ListView to grow or shrink in response 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 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