
今回はコモンコントロールの1つであるツリービューコントロールを作成してみることにしましょう。ツリービューは、階層的なリストを表示しているウィンドウのことです。エクスプローラーのウィンドウの左側にあるフォルダのツリーがまさに代表的なツリービューです。
ツリービューのそれぞれのアイテムは子アイテムを持つことができます。子アイテムを持つアイテムは、 + や - のボタンを持たせることができ、これを押すことで子アイテムのリストを開いたり閉じたりすることができます。
ツリービューを作成する手順は、以下のようになります。
まず最初に InitCommonControls 関数を呼び出してコモンコントロールライブラリを初期化します。これはすべてのコモンコントロールについて共通です。
ツリービューを作成するには、 CreateWindowEx 関数を呼び出すときにウィンドウクラス名を "SysTreeView32" とします。このとき、ウィンドウスタイルとして WS_CHILD (0x40000000) および WS_VISIBLE (0x10000000) を指定します。その他に、ツリービュー固有のスタイルを組み合わせて指定することができます。例えば、親アイテムの横に + や - のボタンを表示するには TVS_HASBUTTONS スタイル (0x0001) を、アイテムを線でつなぎたければ TVS_HASLINES スタイル (0x0002) をそれぞれ指定します。
各アイテムの隣にアイコンイメージを表示させたい場合には、それらのイメージをあらかじめイメージリストとして作成しておく必要があります。
イメージリストの作成については、『イメージリストを使ってみる』の項を参照してください。
イメージリストの準備ができたら、 TVM_SETIMAGELIST メッセージを送信することによって、イメージリストをリストビューにセットします。
#define TVM_SETIMAGELIST 0x1109
TVM_SETIMAGELIST
wParam = iImage;
lParam = himl;
iImage パラメータには、通常は 0 (TVSIL_NORMAL) を指定します。 himl パラメータには、設定するイメージリストのハンドルを指定しておきます。
このメッセージを送った後からでも、イメージリストに新しいイメージを追加していくことができます。
次はアイテムを追加していきます。アイテムを追加するには TVINSERTSTRUCT 構造体に情報を格納してから TVM_INSERTITEM メッセージを送信します。
TVINSERTSTRUCT 構造体は以下のように定義されています。
typedef struct tagTVINSERTSTRUCT {
HTREEITEM hParent; // 親アイテムのハンドル
HTREEITEM hInsertAfter; // 挿入位置を表すアイテムのハンドル
TVITEM item; // 追加するアイテムについての構造体
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;
ツリービューに表示されるアイテムはすべて固有の識別値を持っており、この識別値はアイテムのハンドルと呼ばれます。 hParent メンバには、新しく追加するアイテムの親アイテムのハンドルを指定します。これによって、新しいアイテムがどのアイテムの子アイテムとして追加されるかが指定されます。アイテムをツリービューのルート(一番上の階層)に追加する場合には、 hParent メンバに 0xFFFF0000 (TVI_ROOT) または 0 (NULL) のいずれか指定します。
hInsertAfter メンバには、挿入位置を表すアイテムのハンドルを指定します。新しいアイテムは、ここで指定されたアイテムの次の位置に挿入されることになります。また、リスト中の最初の位置に挿入する場合には 0xFFFF0001 (TVI_FIRST) を、最後の位置に挿入する場合には 0xFFFF0002 (TVI_LAST) を、アルファベット順にソートする場合には 0xFFFF0003 (TVI_SORT) をそれぞれ指定することができます。
item メンバは TVITEM 構造体です。この構造体には、新しく追加するアイテムの情報を格納しておきます。この構造体は入れ子の状態で含まれていることに注意してください。 TVITEM 構造体は以下のように定義されています。
typedef struct tagTVITEM {
UINT mask; // 有効メンバを示すフラグ
HTREEITEM hItem; // アイテムのハンドル
UINT state; // アイテムの状態・イメージ
UINT stateMask; // state のフラグ
LPTSTR pszText; // アイテムの文字列
int cchTextMax; // アイテムの文字列の長さ
int iImage; // イメージのインデックス(非選択時)
int iSelectedImage; // イメージのインデックス(選択時)
int cChildren; // 子アイテムを持つかどうかのフラグ
LPARAM lParam; // アイテムの持つ32ビット値
} TVITEM, *LPTVITEM;
mask メンバは、この構造体の有効メンバを示すフラグです。今回は文字列とイメージを設定するので、0x0001 (LVIF_TEXT) と 0x0002 (TVIF_IMAGE) と 0x0020 (TVIF_SELECTEDIMAGE) を合わせて指定しておきます。
iItem メンバには、新しいアイテムを追加する位置のインデックスを指定します。
iSubItem メンバには 0 を指定します。
pszText メンバには表示する文字列を入れた文字列変数のアドレスを指定します。
iImage メンバには表示するイメージのイメージリスト中におけるインデックスを指定します。選択時のイメージも設定する場合には iSelectedImage メンバにイメージのインデックスを指定します。
他のメンバはここでは関係ないので、どんな値が入っていても無視されます。(今回はとりあえず 0 にしておきます。)
TVINSERTSTRUCT 構造体に情報を入れたら、リストビューに TVM_INSERTITEM メッセージを送信します。
#define TVM_INSERTITEM 0x1100
TVM_INSERTITEM
wParam = 0;
lParam = lpis;
lpis パラメータには、新しいアイテムの情報を格納した TVINSERTSTRUCT 構造体のアドレスを指定します。アイテムが追加されると、戻り値として作成されたアイテムのハンドルが返ります。失敗すると、戻り値として 0 (NULL) が返ります。
さて、実際にスクリプトを書いてみます。今回使用する画像は以下のものです。この画像のサイズは横 (16×4) ピクセル、縦 16 ピクセルで、背景に使われている色の各輝度は、赤 166 (0xA6)、緑 202(0xCA)、青240(0xF0) であるので、背景色を透過させるようにするには、 ImageList_AddMasked 関数のマスク色を指定する引数に 0x00F0CAA6 を指定します。
(treeicon.bmp)
#include "llmod.as"
#module ;###### ビットマップオブジェクト作成モジュール #########
;===============================================================
; 描画中ウィンドウのイメージからビットマップオブジェクト(DIB)作成
; CreateDIB p1, p2, p3, p4
; p1 : HSPウィンドウx座標
; p2 : HSPウィンドウy座標
; p3 : 幅
; p4 : 高さ
; stat : ビットマップのハンドルが返る
;===============================================================
#deffunc CreateDIB int, int, int, int
mref px, 0 ; HSPウィンドウx座標
mref py, 1 ; HSPウィンドウy座標
mref sx, 2 ; xサイズ
mref sy, 3 ; yサイズ
mref stt, 64 ; stat
mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体
; DIBセクションオブジェクト作成
pm = bmscr.4, sx, sy
dllproc "CreateCompatibleBitmap", pm, 3, D_GDI@
hbitmap = stat ; ビットマップオブジェクトのハンドル
; メモリデバイスコンテキスト作成
pm = bmscr.4
dllproc "CreateCompatibleDC", pm, 1, D_GDI@
hdcMemory = stat ; メモリデバイスコンテキストのハンドル
; ビットマップをデバイスコンテキストに選択
pm = hdcMemory, hbitmap
dllproc "SelectObject", pm, 2, D_GDI@
; HSPウィンドウからビットマップにイメージをコピー
pm = hdcMemory, 0, 0, sx, sy, bmscr.4, px, py, $CC0020
dllproc "BitBlt", pm, 9, D_GDI@
; デバイスコンテキストを削除
dllproc "DeleteDC", hdcMemory, 1, D_GDI@
stt = hbitmap ; ビットマップオブジェクトのハンドル
return
#global ;############# モジュール終わり ########################
#module ;######### イメージリスト操作モジュール ################
;===============================================================
; イメージリストの作成
; CreateImageList p1, p2, p3, p4
; p1 : イメージの幅
; p2 : イメージの高さ
; p3 : イメージリストのタイプ
; p4 : イメージの数
; stat : イメージリストのハンドルが返る
;===============================================================
#deffunc CreateImageList int, int, int, int
mref sx, 0 ; イメージの幅
mref sy, 1 ; イメージの高さ
mref flags, 2 ; イメージリストのタイプ
mref num, 3 ; イメージの数
; イメージリストの作成
pm.0 = sx
pm.1 = sy
pm.2 = flags
pm.3 = num
pm.4 = 0
dllproc "ImageList_Create", pm, 5, D_COMCTL@
return
;===============================================================
; イメージリストに描画中ウィンドウのイメージ追加
; AddImageList p1, p2, p3, p4, p5
; p1 : イメージリストのハンドル
; p2 : HSPウィンドウx座標
; p3 : HSPウィンドウy座標
; p4 : 幅
; p5 : 高さ
; p6 : マスクに用いる色
; stat : イメージのインデックスが返る
;===============================================================
#deffunc AddImageList int, int, int, int, int, int
mref himl, 0 ; イメージリストのハンドル
mref cx, 1 ; x座標
mref cy, 2 ; y座標
mref sx, 3 ; xサイズ
mref sy, 4 ; yサイズ
mref crmask, 5 ; マスク生成に用いる色
mref stt, 64 ; stat
; DIBオブジェクトの作成
CreateDIB cx, cy, sx, sy
hbitmap = stat ; ビットマップハンドル
; ビットマップをイメージリストに追加
pm.0 = himl
pm.1 = hbitmap
pm.2 = crmask
dllproc "ImageList_AddMasked", pm, 3, D_COMCTL@
index = stat ; 最初のイメージのインデックス
; ビットマップオブジェクトを削除
dllproc "DeleteObject", hbitmap, 1, D_GDI@
stt = index ; イメージのインデックスをstatに格納
return
;===============================================================
; イメージリストの破棄
; DestroyImageList p1
; p1 : イメージリストのハンドル
;===============================================================
#deffunc DestroyImageList int
mref himl, 0 ; イメージリストのハンドル
; イメージリストを破棄
pm.0 = himl
dllproc "ImageList_Destroy", pm, 1, D_COMCTL@
return
#global ;############# モジュール終わり ########################
#module ;########### ツリービュー操作モジュール ##################
;===============================================================
; 描画中ウィンドウにツリービュー作成
; CreateTreeView p1, p2, p3, p4
; p1 : x座標
; p2 : y座標
; p3 : 幅
; p4 : 高さ
; stat : ツリービューのハンドルが返る
;===============================================================
#deffunc CreateTreeView int, int, int, int
mref cx, 0 ; x
mref cy, 1 ; y
mref sx, 2 ; 幅
mref sy, 3 ; 高さ
mref stt, 64 ; stat
; コモンコントロールライブラリ初期化
dllproc "InitCommonControls", pm, 0, D_COMCTL@
; ツリービュー作成
pm = cx, cy, sx, sy ; 座標、サイズ
pm.4 = 0x50800007 ; WS_VISIBLE | WS_BORDER | WS_CHILD
; | TVS_HASBUTTONS | TVS_HASLINES
; | TVS_LINESATROOT
pm.5 = 0, 0
_makewnd pm, "SysTreeView32"
stt = pm ; ツリービューのハンドル
return
;===============================================================
; ツリービューにイメージリストを設定
; SetTreeImageList p1, p2
; p1 : ツリービューのハンドル
; p2 : イメージリストのハンドル
;===============================================================
#deffunc SetTreeImageList int, int
mref hTree, 0 ; ツリービューのハンドル
mref himl, 1 ; イメージリストのハンドル
; TVM_SETIMAGELIST メッセージ送信
pm = hTree, 0x1109, 0, himl
sendmsg pm
return
;===============================================================
; ツリービューにアイテム追加
; AddTreeItem p1, p2, p3, p4, p5
; p1 : ツリービューのハンドル
; p2 : 表示するテキスト
; p3 : イメージのインデックス
; p4 : 親アイテムのハンドル
; p5 : 挿入位置のアイテムハンドルまたは以下の値
; $FFFF0001 : リストの最初の位置
; $FFFF0002 : リストの最後の位置
; $FFFF0003 : リストをアルファベット順にソート
;===============================================================
#deffunc AddTreeItem int, str, int, int, int
mref hTree, 0 ; ツリービューのハンドル
mref setText, 33 ; 表示するテキスト
mref iImage, 2 ; イメージのインデックス
mref hParent, 3 ; 親アイテムのハンドル
mref hIns, 4 ; 挿入位置のアイテムハンドル
dim bufText, 256
bufText = setText ; いったん別の変数に移しておく
; TVINSERTSTRUCT 構造体
dim tvins, 12
tvins.0 = hParent ; 親アイテムのハンドル
tvins.1 = hIns ; 挿入位置のアイテムハンドル
tvins.2 = 0x0023 ; TVIF_TEXT | TVIF_IMAGE
; | TVIF_SELECTEDIMAGE
getptr tvins.6, bufText ; 文字列のアドレス
tvins.8 = iImage ; イメージインデックス(非選択時)
tvins.9 = iImage ; イメージインデックス(選択時)
; TVM_INSERTITEM メッセージ送信
pm = hTree, 0x1100, 0
getptr pm.3, tvins
sendmsg pm
return
#global ;############# モジュール終わり ########################
; イメージリスト作成 (16×16×4, 24bit, マスクあり)
CreateImageList 16, 16, 25, 4
himl = stat ; イメージリストのハンドル
; イメージリスト作成用バッファウィンドウ
buffer 2,,,0
picload "treeicon.bmp" ; ビットマップの読み込み
; イメージリストにイメージを追加
AddImageList himl, 0, 0, 16*4, 16, 0x00F0CAA6
; ツリービュー作成
gsel 0
CreateTreeView 0, 0, winx, winy
hTree = stat ; ツリービューのハンドル
; ツリービューのイメージリストを設定
SetTreeImageList hTree, himl
; ツリービューのアイテム追加
AddTreeItem hTree,"親アイテム1",0,0,$FFFF0002
hRoot.0 = stat
AddTreeItem hTree,"親アイテム2",0,0,$FFFF0002
hRoot.1 = stat
AddTreeItem hTree, "子アイテム1", 1, hRoot.0, $FFFF0002
hChild.0 = stat
AddTreeItem hTree, "子アイテム2", 1, hRoot.0, $FFFF0002
hChild.1 = stat
AddTreeItem hTree, "子アイテム3", 1, hRoot.1, $FFFF0002
AddTreeItem hTree, "子アイテム4", 1, hRoot.1, $FFFF0002
AddTreeItem hTree, "孫アイテム1", 2, hChild.0, $FFFF0002
AddTreeItem hTree, "孫アイテム2", 2, hChild.1, $FFFF0002
stop