前回のイメージリストを使って、リストビューコントロールのアイテムにアイコンイメージを付けてみたいと思います。詳細表示のリストビューの各アイテムの左側にアイコンが表示されます。
さらに今回は、リストビューの他のスタイルである「大きいアイコン表示」、「小さいアイコン表示」、「一覧表示」に変更する方法についても説明していきましょう。
まずは、リストビューにアイコンとして表示するためのイメージを、イメージリストとして準備しなくてはなりません。
リストビューのタイプによって、使用されるアイコンイメージのサイズが異なります。「大きいアイコン表示」のリストビューでは 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