![]()
![]()
前回のイメージリストを使って、リストビューコントロールのアイテムにアイコンイメージを付けてみたいと思います。詳細表示のリストビューの各アイテムの左側にアイコンが表示されます。
さらに今回は、リストビューの他のスタイルである「大きいアイコン表示」、「小さいアイコン表示」、「一覧表示」に変更する方法についても説明していきましょう。
まずは、リストビューにアイコンとして表示するためのイメージを、イメージリストとして準備しなくてはなりません。
リストビューのタイプによって、使用されるアイコンイメージのサイズが異なります。「大きいアイコン表示」のリストビューでは 32×32 のイメージが使用されます。他のタイプのイメージリストでは 16×16 のイメージが使用されます。したがって、それぞれのタイプに応じた大きさのイメージリストを作成しなければなりません。
リストビューの作成方法は以前にやったものとほとんど同じです。
CreateWindowEx 関数でリストビューを作成する際に、以前はウィンドウスタイルとして LVS_REPORT スタイル (0x0001) を指定していましたが、代わりに LVS_ICON スタイル (0x0000) を指定することで、「大きいアイコン表示」のリストビューを作ることができます。同様に LVS_SMALLICON スタイル (0x0002) を指定すれば「小さいアイコン表示」に、LVS_LIST スタイル (0x0003) を指定すれば「一覧表示」になります。
他にもリストビューにはいろいろなスタイルがあります。各自で試してみましょう。
リストビューが作成できたら、カラムも追加しておきます。
イメージリストとリストビューの準備ができたら、リストビューにイメージリストを割り当てます。イメージリストの割り当てをするには、リストビューに LVM_SETIMAGELIST メッセージを送信します。
#define LVM_SETIMAGELIST 0x1003
LVM_SETIMAGELIST
wParam = iImageList;
lParam = himl;
iImageList パラメータにはイメージリストのタイプを指定します。大きいアイコンを設定する場合には 0x0000 (LVSIL_NORMAL) を、小さいアイコンを設定する場合には 0x0001 (LVSIL_SMALL) を指定します。 himl パラメータには、割り当てるイメージリストのハンドルを指定します。
リストビューのタイプを後で切り替えて使用する場合、あらかじめ両方の大きさのイメージリストを割り当てておけば、タイプを切り替えたときにイメージも自動的に変わります。このとき、アイテムのイメージをイメージリストにおけるインデックスで指定するために、大きいイメージのリストと小さいイメージのリストでは、それぞれのイメージのインデックスを同じにしておく必要があります。
前回イメージリストを作成したときには、イメージリストが不要になったら破棄しなければなりませんでしたが、リストビューに割り当てられたイメージリストは、リストビューが破棄されるときに自動的にイメージリストも破棄されるようになっているため、明示的に破棄する必要はありません。逆に、他のリストビューやその他の目的でも同じイメージリストを使用したい場合、自動的に破棄されては困ります。その場合は、リストビュー作成時にウィンドウスタイルに LVS_SHAREIMAGELISTS (0x0040) スタイルを指定しておくと、イメージリストは自動的に破棄されなくなります。この場合は明示的に破棄するようにしましょう。
次に、アイテムの追加を行ないます。アイテムの追加は、以前の方法と同じく LVITEM 構造体に情報を入れてからリストビューに LVM_INSERTITEM メッセージを送信します。
今回はテキストだけでなくイメージも使用するので、 LVITEM 構造体の mask メンバに 0x0001 | 0x0002 (LVIF_IMAGE | LVIF_TEXT) を指定し、 iItem メンバにはイメージリストにおけるイメージのインデックスを指定します。
以上の方法で、イメージ付きのリストビューが作成できますが、最後に1つ、リストビューのタイプを変更する方法を紹介しておきましょう。
リストビューのタイプを変更するには、リストビューのウィンドウスタイルを変更すればよいということが分かると思います。ウィンドウスタイルの変更は SetWindowLong 関数によって行なうことができます。
LONG SetWindowLongA(
HWND hWnd, // ウィンドウハンドル
int nIndex, // 変更するデータの指定
LONG dwNewLong // 新しい値
);
SetWindowLong 関数の第2引数(nIndex パラメータ)に -16 (GWL_STYLE) を指定すると、ウィンドウスタイルが第3引数(dwNewLong パラメータ)で指定したものに変更されます。この値として、新しいリストビューのタイプを指定すればよいのです。ただし、タイプ以外に WS_CHILD スタイルや、必要ならば WS_VISIBLE スタイルも合わせて指定しなければなりません。また、変更する以前に他のスタイルも指定していたならば、それも合わせて指定する必要があります。
では、リストビューのタイプのみを変更して、他のスタイルは変更しないようにするにはどうしたらよいでしょうか?それには、変更する前にいったんウィンドウスタイルを取得し、リストビューのタイプに関係する部分のみを変更してからウィンドウに設定すればよいのです。
ウィンドウスタイルを取得するには GetWindowLong 関数を呼び出します。
LONG GetWindowLongA(
HWND hWnd, // ウィンドウハンドル
int nIndex // 取得するデータの指定
);
GetWindowLong 関数の第2引数(nIndex パラメータ)に -16 (GWL_STYLE) を指定すると、関数の戻り値としてウィンドウスタイルが返ります。
リストビューのウィンドウスタイルを示す32ビット値の中で、リストビューのタイプをつかさどるのはビット1〜2になります。この部分を無効化する(0 にする)には、 GetWindowLong 関数で取得したウィンドウスタイルと値 0xFFFFFFFC をAND結合(ビット演算子 & で結合)します。さらに、それに新しいスタイルをOR結合(ビット演算子 | で結合)すれば、目的のウィンドウスタイルを表す32ビット値になります。この値を SetWindowLong 関数で指定すれば、リストビューのタイプのみを変更することができます。
; 現在のウィンドウスタイルを取得 pm = hList, -16 dllproc "GetWindowLongA", pm, 2, D_USER style = stat ; リストビューの表示形式を LVS_SMALLICON に変更 style = style & 0xFFFFFFFC | 0x0002 ; 新しいウィンドウスタイルを設定 pm = hList, -16, style dllproc "SetWindowLongA", pm, 3, D_USER
LLMOD モジュールでは SetWindowLong 関数および GetWindowLong 関数を呼び出すモジュール命令として setwndlong 命令を定義しています。 SetWindowLong 関数を呼び出すには dllproc 命令の代わりにこの命令を使います。 GetWindowLong 関数を呼び出すには、第2パラメータに 1 を指定します。例えば、上のスクリプトは次のようになります。
; 現在のウィンドウスタイルを取得 pm = hList, -16 setwndlong pm, 1 style = stat ; リストビューの表示形式を LVS_SMALLICON に変更 style = style & 0xFFFFFFFC | 0x0002 ; 新しいウィンドウスタイルを設定 pm = hList, -16, style setwndlong pm
さて、実際にスクリプトを書いてみます。今回使用する画像は前回と同じく以下のものです。この画像のサイズは横 (32×4) ピクセル、縦 32 ピクセルで、背景に使われている色の各輝度は、赤 166 (0xA6)、緑 202(0xCA)、青240(0xF0) であるので、背景色を透過させるようにするには、 ImageList_AddMasked 関数のマスク色を指定する引数に 0x00F0CAA6 を指定すれば OK です。
(iconlist.bmp)
次のスクリプトを実行させると、ボタンを押すたびに、リストビューのタイプが「大きいアイコン表示」→「詳細表示」→「小さいアイコン表示」→「一覧表示」と変化していきます。
残念ながら「アイコン表示」ではアイテムをドラッグできないようですね。おそらくは自前で処理しなくてはならないのかもしれません。いずれ機会があったらやってみたいと思いますが。
#include "llmod.as"
#module ;###### ビットマップオブジェクト作成モジュール #########
;===============================================================
; CreateDIB DIBセクションオブジェクト作成
;===============================================================
#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 イメージリストの作成
;===============================================================
#deffunc CreateImageList int, int, int, int
mref sx, 0 ; イメージの幅
mref sy, 1 ; イメージの高さ
mref flags, 2 ; イメージリストのタイプ
mref num, 3 ; イメージの数
; イメージリストの作成
pm = sx, sy, flags, num, 0
dllproc "ImageList_Create", pm, 5, D_COMCTL@
return
;===============================================================
; AddImageList イメージリストに描画中ウィンドウのイメージ追加
;===============================================================
#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 = himl, hbitmap, crmask
dllproc "ImageList_AddMasked", pm, 3, D_COMCTL@
index = stat ; 最初のイメージのインデックス
; ビットマップオブジェクトを削除
dllproc "DeleteObject", hbitmap, 1, D_GDI@
stt = index ; イメージのインデックスをstatに格納
return
;===============================================================
; DestroyImageList イメージリストの破棄
;===============================================================
#deffunc DestroyImageList int
mref himl, 0 ; イメージリストのハンドル
; イメージリストを破棄
pm = himl
dllproc "ImageList_Destroy", pm, 1, D_COMCTL@
return
#global ;############# モジュール終わり ########################
#module ;########## リストビュー操作モジュール #################
;===============================================================
; CreateListView リストビュー作成
;===============================================================
#deffunc CreateListView int, int, int, int, int, int, int
mref cx, 0 ; x座標
mref cy, 1 ; y座標
mref sx, 2 ; 幅
mref sy, 3 ; 高さ
mref type, 4 ; リストビューのタイプ
mref himl, 5 ; イメージリスト(大きいアイコン)
mref himlsmall, 6 ; イメージリスト(小さいアイコン)
mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体
mref stt, 64 ; stat
; コモンコントロールライブラリ初期化
dllproc "InitCommonControls", pm, 0, D_COMCTL@
; リストビューコントロールの作成
pm.0 = cx, cy, sx, sy ; 座標、サイズ
pm.4 = 0x50000000 | type ; WS_VISIBLE | WS_CHILD | type
pm.5 = 0 ; 親ウィンドウ(0のとき描画中ウィンドウ)
pm.6 = 0 ; 拡張ウィンドウスタイル
_makewnd pm, "SysListView32"
hList = pm ; リストビューのハンドル
; イメージリスト(大きいアイコン)の追加
if himl {
; LVM_SETIMAGELIST メッセージ送信
pm = hList, 0x1003, 0, himl
sendmsg pm
}
; イメージリスト(小さいアイコン)の追加
if himlsmall {
; LVM_SETIMAGELIST メッセージ送信
pm = hList, 0x1003, 1, himlsmall
sendmsg pm
}
stt = hList ; stat にリストビューのハンドルを格納
return
;===============================================================
; AddListColumn リストビューにカラムを追加
;===============================================================
#deffunc AddListColumn str, int, int, int, int
mref setText, 32 ; ヘッダ文字列
mref hList, 1 ; リストビューのハンドル
mref index, 2 ; カラムのインデックス
mref alm, 3 ; 配置(0:左 1:右 2:中央)
mref wid, 4 ; カラムの幅
sdim szText, 256
szText = setText ; いったん別の変数に移しておく
; LVCOLUMN 構造体
lvcolumn.0 = 0x000F ; LVCF_FMT | LVCF_WIDTH | LVCF_TEXT
; | LVCF_SUBITEM
lvcolumn.1 = alm
lvcolumn.2 = wid
getptr lvcolumn.3, szText
lvcolumn.4 = 0
lvcolumn.5 = index
; LVM_INSERTCOLUMN メッセージ送信
pm = hList, 0x101B, index
getptr pm.3, lvcolumn
sendmsg pm
return
;===============================================================
; AddListItem リストビューにアイテム追加
;===============================================================
#deffunc AddListItem str, int, int, int
mref setText, 32 ; 文字列
mref hList, 1 ; リストビューのハンドル
mref index, 2 ; アイテムのインデックス
mref indeximg, 3 ; アイテムのイメージのインデックス
sdim szText, 256
szText = setText ; いったん別の変数に移しておく
; LVITEM 構造体
lvitem.0 = 0x0003 ; LVIF_TEXT | LVIF_TEXT
lvitem.1 = index ; インデックス
lvitem.2 = 0
getptr lvitem.5, szText
lvitem.7 = indeximg ; イメージのインデックス
; LVM_INSERTITEM メッセージ送信
pm = hList, 0x1007, 0
getptr pm.3, lvitem
sendmsg pm
return
;===============================================================
; SetListItem リストビューのサブアイテム設定
;===============================================================
#deffunc SetListItem str, int, int, int
mref setText, 32 ; サブアイテム文字列
mref hList, 1 ; リストビューのハンドル
mref index, 2 ; アイテムのインデックス
mref indexsub, 3 ; サブアイテムのインデックス
sdim szText, 256
szText = setText ; いったん別の変数に移しておく
; LVITEM 構造体
lvitem.0 = 0x0001 ; LVIF_TEXT
lvitem.1 = index ; インデックス
lvitem.2 = indexsub
getptr lvitem.5, szText
; LVM_SETITEM メッセージ送信
pm = hList, 0x1006, 0
getptr pm.3, lvitem
sendmsg pm
return
;===============================================================
; GetListItem リストビューアイテムの文字列取得
;===============================================================
#deffunc GetListItem val, int, int, int, int
mref retText, 24 ; 取得文字列を格納する文字列変数
mref hList, 1 ; リストビューのハンドル
mref index, 2 ; アイテムのインデックス
mref indexsub, 3 ; サブアイテムのインデックス
mref cch, 4 ; バッファサイズ
; LVITEM 構造体
lvitem.0 = 0x0001 ; LVIF_TEXT
lvitem.1 = index ; アイテムのインデックス
lvitem.2 = indexsub ; サブアイテムインデックス
getptr lvitem.5, retText ; バッファのアドレス
lvitem.6 = cch ; バッファのサイズ
; LVM_GETITEM メッセージ送信
pm = hList, 0x1005, 0
getptr pm.3, lvitem
sendmsg pm
return
;===============================================================
; DelListItem リストビューアイテムの削除
;===============================================================
#deffunc DelListItem int, int
mref hList, 0 ; リストビューのハンドル
mref index, 1 ; アイテムのインデックス
; LVM_DELETEITEM メッセージ送信
pm = hList, 0x1008, index, 0
sendmsg pm
return
;===============================================================
; GetSelListItem 選択されているリストアイテムの取得
;===============================================================
#deffunc FindSelListItem int, int
mref hList, 0 ; リストビューのハンドル
mref index, 1 ; アイテムのインデックス
; LVM_GETNEXTITEM メッセージ送信
pm = hList, 0x100C
pm.2 = index ; 検索開始インデックス
pm.3 = 0x0002 ; LVNI_ALL | LVNI_SELECTED
sendmsg pm
return
;===============================================================
; SetListType リストビューのタイプの変更
;===============================================================
#deffunc SetListType int, int
mref hList, 0 ; リストビューのハンドル
mref type, 1 ; 変更するタイプ
; 現在のウィンドウスタイルを取得
pm = hList, -16
setwndlong pm, 1
style = stat
; リストビューの表示形式を変更
style = style & 0xFFFFFFFC | type
; 新しいウィンドウスタイルを設定
pm = hList, -16, style
setwndlong pm
return
#global ;############# モジュール終わり ########################
; ビットマップファイルの読み込み
buffer 2,,, 0 ; フルカラーモード
picload "iconlist.bmp"
; 大きいアイコン(32×32)イメージリスト作成
CreateImageList 32, 32, 0x0018 | 0x0001, 4
himg1 = stat ; イメージリストのハンドル
AddImageList himg1, 0, 0, 32*4, 32, 0x00F0CAA6
; イメージを縮小
pos 0, 0
gzoom 16*4, 16, 2, 0, 0, 32*4, 32
; 小さいアイコン(16×16)イメージリスト作成
CreateImageList 16, 16, 0x0018 | 0x0001, 4
himg2 = stat ; イメージリストのハンドル
AddImageList himg2, 0, 0, 16*4, 16, 0x00F0CAA6
gsel 0
objsize winx, 25
button "リストタイプ変更", *lb_change_listtype
; リストビュー作成
CreateListView 0, 25, winx, winy-25, 0, himg1, himg2
hList = stat ; リストビューのハンドル
; カラムの追加
AddListColumn "名前", hList, 0, 0, 100
AddListColumn "読み", hList, 1, 0, 100
; アイテムの追加・サブアイテムの設定
AddListItem "在原業平", hList, 0, 0
SetListItem "ありわらのなりひら", hList, 0, 1
AddListItem "僧正遍昭", hList, 1, 1
SetListItem "そうじょうへんじょう", hList, 1, 1
AddListItem "喜撰法師", hList, 2, 2
SetListItem "きせんほうし", hList, 2, 1
AddListItem "大伴黒主", hList, 3, 3
SetListItem "おおとものくろぬし", hList, 3, 1
AddListItem "文屋康秀", hList, 4, 0
SetListItem "ふんやのやすひで", hList, 4, 1
AddListItem "小野小町", hList, 5, 1
SetListItem "おののこまち", hList, 5, 1
stop
*lb_change_listtype
; リストビューのタイプを変更
type = (type + 1) \ 4
SetListType hList, type
stop