リストビューでアイコンを使ってみる

リストビューのアイコン表示




前回のイメージリストを使って、リストビューコントロールのアイテムにアイコンイメージを付けてみたいと思います。詳細表示のリストビューの各アイテムの左側にアイコンが表示されます。

さらに今回は、リストビューの他のスタイルである「大きいアイコン表示」、「小さいアイコン表示」、「一覧表示」に変更する方法についても説明していきましょう。


まずは、リストビューにアイコンとして表示するためのイメージを、イメージリストとして準備しなくてはなりません。

リストビューのタイプによって、使用されるアイコンイメージのサイズが異なります。「大きいアイコン表示」のリストビューでは 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