リストビューを作成してみる ACT-2

前回はリストビューの作成と、アイテムの追加についてを説明しました。今回は、作成されたリストビューからアイテムの内容を取得して、それを表示できるようにしてみましょう。また、アイテムの削除についてや、アイテムを検索する方法についてもやってみます。

アイテム情報の取得

リストビューのアイテムの内容を取得するには、 LVITEM 構造体に必要な情報を格納しておいてから、その構造体のアドレスをパラメータとしてリストビューに LVM_GETITEM メッセージを送信します。


前回も示しましたが、 LVITEM 構造体は以下のように定義されています。

typedef struct _LVITEM {
    UINT   mask;          // 有効メンバを示すフラグ
    int    iItem;         // アイテムのインデックス
    int    iSubItem;      // サブアイテムインデックス
    UINT   state;         // アイテムの状態・イメージ
    UINT   stateMask;     // state のフラグ
    LPTSTR pszText;       // アイテムの文字列
    int    cchTextMax;    // pszTextのサイズ
    int    iImage;        // イメージのインデックス
    LPARAM lParam;        // アイテムの持つ32ビット値
} LVITEM, FAR *LPLVITEM;

mask メンバは、この構造体の有効メンバを示すフラグです。アイテム(またはサブアイテム)の文字列を取得したい場合は 0x0001 (LVIF_TEXT) を指定しておきます。 0x0008 (LVIF_STATE) を指定すると、アイテムの状態を取得することもできます。これらのフラグは値を組み合わせて指定します。

iItem メンバには、状態を取得したいアイテムの位置のインデックスを指定します。

iSubItem メンバには、アイテムの文字列(1列目のカラムの文字列)や状態を取得する場合には 0 を指定します。また、サブアイテムの文字列(2列目以降のカラムの文字列)を取得したい場合には、 1 以降のサブアイテムのインデックスを指定します。

mask メンバで 0x0001 (LVIF_TEXT) を指定した場合は、pszText メンバに取得した文字列を格納するバッファのアドレスを、 cchTextMax メンバにはそのバッファのサイズを格納しておかなければなりません。


LVITEM 構造体に必要な情報を格納したら、リストビューに LVM_GETITEM メッセージを送信します。

#define  LVM_GETITEM    0x1005

LVM_GETITEM
    wParam = 0;
    lParam = pitem;

pitem パラメータには、情報を格納した LVITEM 構造体のアドレスを指定します。情報の取得が成功すると、 LVITEM 構造体のそれぞれのメンバに情報が格納され、戻り値として 0 以外の値が返ります。情報の取得に失敗した場合は 0 が返ります。

アイテムの削除

次は、アイテムを削除する方法です。

アイテムを削除するには、リストビューに LVM_DELETEITEM メッセージを送信します。

#define  LVM_DELETEITEM    0x1008

LVM_DELETEITEM
    wParam = iItem;
    lParam = 0;

iItem パラメータには、削除するアイテムのインデックスを指定します。削除に成功すると、戻り値として 0 以外の値が、失敗すると 0 が返ります。

アイテムの検索

最後に、アイテムを検索する方法です。

アイテムを検索するのには2つのタイプがあり、それによって検索の方法も異なってきます。

特殊な状態を持つアイテムの検索

まず、特殊な状態を持つアイテムを検索する場合についてです。

特殊な状態を持つアイテムを検索するには、リストビューに LVM_GETNEXTITEM メッセージを送ります。

#define  LVM_GETNEXTITEM    0x100C

LVM_GETNEXTITEM
    wParam = iStart;
    lParam = flags;

iStart パラメータには、検索を開始するアイテムのインデックスを指定します。指定されたアイテム自身は検索の対象にはなりません。リストの最初から検索をする場合には -1 を指定します。

flags パラメータには、検索する方向と、どの状態のアイテムを検索するのかを示すフラグを指定します。これは以下の値になります。

意味
0x0000 (LVNI_ALL)

指定されたアイテムの後に続くアイテムを検索します。(デフォルト)

0x0001 (LVNI_FOCUSED)

フォーカスを持つアイテムを検索します。

0x0002 (LVNI_SELECTED)

選択されているアイテムを検索します。

0x0004 (LVNI_CUT)

カット・アンド・ペーストの対象としてマークされているアイテムを検索します。

0x0008 (LVNI_DROPHILITED)

ドラッグ・アンド・ドロップのターゲットとしてハイライト表示されているアイテムを検索します。

0x0100 (LVNI_ABOVE)

指定されたアイテムの上にあるアイテムを検索します。

0x0200 (LVNI_BELOW)

指定されたアイテムの下にあるアイテムを検索します。

0x0400 (LVNI_TOLEFT)

指定されたアイテムの左にあるアイテムを検索します。

0x0800 (LVNI_TORIGHT)

指定されたアイテムの右にあるアイテムを検索します。

該当するアイテムがあった場合、戻り値としてそのアイテムのインデックスが返ります。該当するアイテムがなかった場合は、-1 が返ります。

指定された文字列を持つアイテムの検索

次に、指定された文字列を持つアイテムなどを検索する場合についてです。

この場合、 LVFINDINFO 構造体に検索のための情報を格納した上で、その構造体のアドレスをパラメータとして、リストビューに LVM_FINDITEM メッセージを送ります。

typedef struct tagLVFINDINFO {
    UINT    flags;         // 検索のタイプを示すフラグ
    LPCTSTR psz;           // 文字列のアドレス
    LPRARAM lParam;        // アイテムの持つ32ビット値
    POINT   pt;            // アイテムの位置
    UINT    vkDirection;   // 検索方向を示す仮想キーコード
} LVFINDINFO, FAR* LPFINDINFO;

この構造体についての説明はここでは省きます。

#define  LVM_FINDITEM    0x100D

LVM_FINDITEM
    wParam = iStart;
    lParam = plvfi;

iStart パラメータには、検索を開始するアイテムのインデックスを指定します。指定されたアイテム自身は検索の対象にはなりません。リストの最初から検索をする場合には -1 を指定します。

plvfi パラメータには、検索に必要な情報を格納した LVFINDINFO 構造体のアドレスを指定します。

該当するアイテムが見つかった場合、戻り値としてそのアイテムのインデックスが返ります。該当するアイテムが見つからなかった場合は、-1 が返ります。

サンプルスクリプト

さて、実際にスクリプトを書いてみることにしましょう。

前回のスクリプトに、アイテム文字列取得・アイテム削除・選択アイテム取得のためのモジュール命令が追加されています。

このスクリプトでは、マウスクリックなどによって選択されたアイテムの情報表示や削除を行なっています。[Alt]キーや[Shift]キーなどを押しながら選ぶことによって複数のアイテムが同時に選択された場合でも対応できるようにしてあります。

    #include "llmod.as"

    #module ;============= リストビュー操作モジュール ===============

    ;----------------------------------------------------------------
    ; CreateListView リストビュー作成
    ;----------------------------------------------------------------
    #deffunc CreateListView int, int, int, int
    mref cx, 0                 ; x座標
    mref cy, 1                 ; y座標
    mref sx, 2                 ; 幅
    mref sy, 3                 ; 高さ
    mref bmscr, 67             ; 描画中ウィンドウのBMSCR構造体
    mref stt, 64               ; stat

    ; コモンコントロールライブラリ初期化
    dllproc "InitCommonControls", pm, 0, D_COMCTL@

    ; リストビューコントロールの作成
    pm.0 = cx, cy, sx, sy      ; 座標、サイズ
    pm.4 = 0x50000001          ; WS_VISIBLE | WS_CHILD | LVS_REPORT
    pm.5 = 0                   ; 親ウィンドウ(0のとき描画中ウィンドウ)
    pm.6 = 0                   ; 拡張スタイル
    _makewnd pm, "SysListView32"
    stt = pm.0                 ; 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
    mref setText, 32           ; 文字列
    mref hList, 1              ; リストビューのハンドル
    mref index, 2              ; アイテムのインデックス

    sdim szText, 256
    szText = setText           ; いったん別の変数に移しておく

    ; LVITEM 構造体
    lvitem.0 = 0x0001          ; LVIF_TEXT
    lvitem.1 = index           ; インデックス
    lvitem.2 = 0
    getptr lvitem.5, szText

    ; 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

    #global ;================= モジュール終わり =====================


    objsize winx/2, 25 : objmode 1
    pos 0, 0  : button "選択アイテムの情報表示", *lb_mesitem
    pos winx/2, 0 : button "選択アイテム削除", *lb_delitem

    CreateListView 0, 25, winx, winy-25
    hList = stat

    AddListColumn "名前", hList, 0, 0, 100
    AddListColumn "読み", hList, 1, 0, 100

    AddListItem "在原業平", hList, 0
    SetListItem "ありわらのなりひら", hList, 0, 1

    AddListItem "僧正遍昭", hList, 1
    SetListItem "そうじょうへんじょう", hList, 1, 1

    AddListItem "喜撰法師", hList, 2
    SetListItem "きせんほうし", hList, 2, 1

    AddListItem "大伴黒主", hList, 3
    SetListItem "おおとものくろぬし", hList, 3, 1

    AddListItem "文屋康秀", hList, 4
    SetListItem "ふんやのやすひで", hList, 4, 1

    AddListItem "小野小町", hList, 5
    SetListItem "おののこまち", hList, 5, 1

    stop

*lb_mesitem
    ; 選択されているアイテムの情報を表示
    sdim buf1, 256             ; アイテムの文字列を格納する変数
    sdim buf2, 256             ; サブアイテムの文字列を格納する変数
    ; 複数のアイテムが選択されている場合に対応
    idx = -1
    repeat
        FindSelListItem hList, idx
        idx = stat
        if idx == -1 : break
        GetListItem buf1, hList, idx, 0, 128
        GetListItem buf2, hList, idx, 1, 128
        buf1 += "\n"+buf2
        dialog buf1, 0, "情報表示"
    loop
    stop

*lb_delitem
    ; 選択されているアイテムをリストビューから削除
    ; 複数のアイテムが選択されている場合に対応
    idx = -1
    repeat
        FindSelListItem hList, idx
        idx = stat
        if idx == -1 : break
        DelListItem hList, idx
        idx--                  ; アイテム削除によるインデックスのずれを補正
    loop
    stop