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

リストビューコントロール

今回は、コモンコントロールの1つであるリストビューコントロールを作成してみることにしましょう。

リストビューとは右の図のようなコントロールです。いろいろなアプリケーションで使われていて、よく見かけると思います。また、もっとも身近なリストビューは、エクスプローラの右側のウィンドウです。「表示」メニューには「大きいアイコン」「小さいアイコン」「一覧表示」「詳細表示」があります。「詳細表示」にすると、右に示したコントロールと同じものが表示されると思います。

今回作成するリストビューはアイコンはありませんが、いわゆる「詳細表示」のリストビューを作ります。

リストビューの作成手順

リストビューを作成する手順は、以下のようになります。

  1. InitCommonControls 関数を実行する。
  2. クラス名を "SysListView32" とし、ウィンドウスタイルに LVS_REPORT スタイルを加えて CreateWindowEx 関数を呼び出しリストビューを作成する。
  3. リストビューに LVM_INSERTCOLUMN メッセージを送信し、新しいカラム(列)を追加する。
  4. リストビューに LVM_INSERTITEM メッセージを送信し、新しいアイテムを追加する。
  5. リストビューに LVM_SETITEM メッセージを送信し、サブアイテムを設定する。

1.コモンコントロールライブラリ初期化

まず最初に InitCommonControls 関数を呼び出します。これはすべてのコモンコントロールについて共通です。

2.コントロールの作成

リストビューを作成するには、 CreateWindowEx 関数を呼び出すときに、ウィンドウクラス名を "SysListView32" とします。このとき、ウィンドウスタイルとして WS_CHILD (0x40000000) および WS_VISIBLE (0x10000000) を指定します。その他に、今回は LVS_REPORT (0x0001) を指定します。このスタイルは、エクスプローラで「詳細表示」を選択したときと同じリストビューを作成するためのものです。

3.カラムの追加

以上の操作で作成されたリストビューには、まだ何も表示されていません。ここにまず、カラム(列)を追加していく必要があります。カラムを追加するには、まず LVCOLUMN 構造体に必要な情報を格納しておいてから、その構造体のアドレスをパラメータとしてリストビューに LVM_INSERTCOLUMN メッセージを送信します。


LVCOLUMN 構造体は以下のように定義されています。

typedef struct _LVCOLUMN {
    UINT mask;         // 有効メンバを示すフラグ
    int  fmt;          // 列の配置
    int  cx;           // カラムの幅
    LPTSTR pszText;    // カラムのヘッダの文字列
    int  cchTextMax;   // pszTextのサイズ
    int  iSubItem;     // カラムのサブアイテムインデックス
} LVCOLUMN, FAR *LPLVCOLUMN;

mask メンバには有効なメンバを表すフラグを指定します。ここでは、すべてのメンバを有効にするために、 0x0001 (LVCF_FMT)、 0x0002 (LVCF_WIDTH)、 0x0004 (LVCF_TEXT)、 0x0008 (LVCF_SUBITEM) を組み合わせた値を指定します。

fmt メンバには、そのカラムに表示される文字列の表示位置を指定します。 0x0000 (LVCFMT_LEFT) を指定すると、左に表示されます。 0x0001 (LVCFMT_RIGHT) を指定すると、右に表示されます。 0x0002 (LVCFMT_CENTER) を指定すると、中央に表示されます。

cx メンバには、カラムの幅をピクセル単位で指定します。

pszText メンバには、ヘッダに表示する文字列のアドレスを指定します。

cchTextMax はここでは無視されます。 0 にしておきましょう。

iSubItem はこのカラムに関連付けられるサブアイテムのインデックスを指定します。後でアイテムを追加して各カラムに文字列を設定するときにこの値を指定すれば、このカラムに表示されます。


LVCOLUMN 構造体に情報を入れたら、 LVM_INSERTCOLUMN メッセージを送信します。

#define  LVM_INSERTCOLUMN    0x101B

LVM_INSERTCOLUMN
    wParam = iCol;
    lParam = pcol;

iCol パラメータには、新しいカラムを挿入する位置のインデックスを指定します。ここで指定した位置にカラムが追加されます。このインデックスは 0 から始まる値で、最も左のカラムが 0 に、その右隣のカラムが 1 になります。

pcol パラメータには、先ほど情報を入れた LVCOLUMN 構造体のアドレスを指定します。カラムが作成されると、戻り値として作成されたカラムのインデックスが返ります。作成に失敗すると -1 が返ります。

4.アイテムの追加

さて、これでカラムができたので、次はアイテムを追加していきます。アイテムを追加するには LVITEM 構造体に情報を格納してから LVM_INSERTITEM メッセージを送信します。


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) を指定しておきます。

iItem メンバには、新しいアイテムを追加する位置のインデックスを指定します。このインデックスは 0 から始まる値で、最も上のアイテムが 0 に、その1つ下のアイテムが 1 になります。

iSubItem メンバには 0 を指定します。

pszText メンバには表示する文字列を入れた文字列変数のアドレスを指定します。

他のメンバはここでは関係ないので、どんな値が入っていても無視されます。(今回はとりあえず 0 にしておきます。)


LVITEM 構造体に情報を入れたら、リストビューに LVM_INSERTITEM メッセージを送ります。

#define  LVM_INSERTITEM    0x1007

LVM_INSERTITEM
    wParam = 0;
    lParam = pitem

pitem パラメータには、新しいアイテムの情報を格納した LVITEM 構造体のアドレスを指定します。アイテムが追加されると、戻り値として作成されたアイテムのインデックスが返ります。失敗すると、戻り値として -1 が返ります。

5.サブアイテムの設定

アイテムが追加できたので、次はこのアイテムが持つサブアイテムを設定します。サブアイテムというのは、簡単に言えば、そのアイテムの2列目以降に表示されている文字列のことです。

サブアイテムを設定するには LVITEM 構造体に情報を格納してから LVM_SETITEM メッセージを送ります。


LVITEM 構造体についてはアイテム追加時とほとんど変わりませんが、ここでは iSubItem メンバにサブアイテムのインデックスを指定する必要があります。このインデックスは 1 から始まる値で、リストビューの2列目がインデックス1にあたります。ちなみに、ここで iSubItem メンバに 0 を指定すると、先ほど追加されたアイテムの文字列が変更されます。


LVITEM 構造体に情報を入れたら、リストビューに LVM_SETITEM メッセージを送ります。

#define  LVM_SETITEM    0x1006

LVM_SETITEM
    wParam = 0;
    lParam = pitem;

pitem パラメータは、サブアイテムの情報を格納した LVITEM 構造体のアドレスを指定します。設定に成功すると、戻り値として 0 以外の値が、失敗すると 0 が返ります。

サンプルスクリプト

さて、実際にスクリプトを書いてみます。今回は、それぞれの機能ごとにモジュール命令を定義してみます。

リストビューの作成には、 CreateWindowEx 関数を呼び出すのに、LLMODモジュールの _makewnd 命令を使用しています。

    #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

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


    CreateListView 0, 0, winx, winy
    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

次回はアイテムの情報取得や削除などです。