|
1.概要
本ページは、私がフリーソフトを作成する際に使用したリストビューの
コーディング手法を紹介することを目的としています。
紹介する手法は、必ずしもこれでないと実現できないというわけではありません。
方法は他にもたくさんあると思います。
2.私が使用した手法
(1)列の追加
(2)行の追加
(3)全ての行を消去
(4)1行選択可能にする
(5)グリッド線を入れる
(6)ダブルクリックイベント
(7)選択中の行を知る
(8)指定セルのデータを取得
(9)全項目数を知る
(10)指定セルのデータを書き換え
(11)指定行の背景色変更
(1) 列の追加(ListView_InsertColumn)
これは、リストビューで一番最初に実行する作業で、これにより、
リストビューのヘッダを作ります。
(書き忘れていましたが、これの前にcommctrl.hのインクルード、
comctl32.libの追加、InitCommonControls関数のコールが要ります)
ヘッダの追加は、ListView_InsertColumnマクロを使用します。
以下にマクロ引数の説明を書きます。
<ListView_InsertColumnマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
・第2引数 int iCol
・・・挿入するカラム(列)のインデックスを指定します。
・第3引数 const LPLVCOLUMN FAR pcol
・・・新しいカラムの属性を含んでいるLV_COLUMN構造体の
アドレスを指定します。
では、以下に列を2つ追加する例を書きます。
例)HWND hList;
LV_COLUMN lvcol;
hList = GetDlgItem(hWnd, リストビューID);
lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvcol.fmt = LVCFMT_LEFT;
lvcol.cx = 100;
lvcol.pszText = "列1";
lvcol.iSubItem = 0;
ListView_InsertColumn(hList, 0, &lvcol);
lvcol.cx = 150;
lvcol.pszText = "列2";
lvcol.iSubItem = 1;
ListView_InsertColumn(hList, 1, &lvcol);
上記で初めて出てきた構造体があります。そう、LV_COLUMNです。
この構造体の簡単な説明を以下に書きます。
<LV_COLUMN構造体>
・UINT mask ・・・どういった設定を有効にするか指定するマスクです。
・int fmt ・・・配置位置を指定します。
・int cx ・・・列幅を指定します。
・LPTSTR pszText ・・・列に表示する文字列を指定します。
・int cchTextMax・・・pszTextのバッファサイズを指定します。
アイテム情報を取得する時だけ使用する。
・int iSubItem ・・・サブアイテムのインデックス番号を指定します。
出来上がったリストビューは、こんな感じです。
(2)行の追加(ListView_InsertItem・ListView_SetItem)
リストビューでヘッダを作成したら、データを登録しなければ、
リストビューの意味がありません。
行の追加は、2段階で設定します。
まず、ListView_InsertItemマクロで1カラム目の登録、
次に、ListView_SetItemマクロで2カラム目以降の登録、
という風に行います。
以下に、マクロ引数の説明を書きます。
<ListView_InsertItemマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
・第2引数 const LV_ITEM FAR *pitem
・・・アイテム属性を指定するLVITEM構造体のアドレスを
指定します。
<ListView_SetItemマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
・第2引数 const LV_ITEM FAR *pitem
・・・アイテム属性を指定するLVITEM構造体の
アドレスを指定します。
では、以下に行を2つ追加する例を書きます。
例)HWND hList;
LV_ITEM item;
hList = GetDlgItem(hWnd, リストビューID);
item.mask = LVIF_TEXT;
item.pszText = "1行目1カラム目";
item.iItem = 0;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "1行目2カラム目";
item.iItem = 0;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目1カラム目";
item.iItem = 1;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目2カラム目";
item.iItem = 1;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
上記で初めて出てきた構造体がまたあります。
そう、LV_ITEMです。この構造体の簡単な説明を以下に書きます。
<LV_ITEM構造体>
・UINT mask ・・・どういった設定を有効にするか指定するマスクです。
・int iItem ・・・追加する行位置を指定します。
・int iSubItem ・・・追加する列位置を指定します。
・UINT state ・・・項目の現在状態を指定します。
・UINT stateMask ・・・項目の有効状態を指定します。
・LPTSTR pszText ・・・セルに表示する文字列を指定します。
・int cchTextMax・・・pszTextのバッファサイズを指定します。
アイテム情報を取得時だけ使用する。
・int iImage ・・・アイコンを格納しているイメージリストの
インデックス値を指定します。
・LPARAM lParam ・・・ソートする際に使用するユーザが
定義する値を指定します。
出来上がったリストビューは、こんな感じです。
(3)全ての行を消去(ListView_DeleteAllItems)
リストビューで行を追加した後、もう一度データを一から登録しなおしたい
場合が出てくると思います。
そんな時に、ListView_DeleteAllItemsマクロを使用し、全ての行の消去します。
以下に、マクロ引数の説明を書きます。
<ListView_InsertItemマクロ>
・第1引数 HWND hwnd ・・・リストビューのウィンドウハンドルを指定します。
では、以下に全ての行を消去する例を書きます。
例)HWND hList;
hList = GetDlgItem(hWnd, リストビューID);
ListView_DeleteAllItems(hList);
消去後のリストビューは、こんな感じです。
(4)1行選択可能にする(LVS_EX_FULLROWSELECT)
リストビューは、拡張設定しないままだと、1列目のセルしか選択出来ません。
1行全体を選択可能にするには、ListView_GetExtendedListViewStyleマクロと
ListView_SetExtendedListViewStyleマクロを使用します。
ListView_GetExtendedListViewStyleマクロは、リストビューの
現在の拡張スタイルを取得します。
このマクロで取得したスタイルに追加したいスタイルを掛け合わせ、
ListView_SetExtendedListViewStyleマクロでリストビューの
拡張スタイルを設定します。
以下に、マクロ引数の説明を書きます。
<ListView_GetExtendedListViewStyleマクロ>
・第1引数 HWND hwnd ・・・リストビューのウィンドウハンドルを指定します。
<ListView_SetExtendedListViewStyleマクロ>
・第1引数 HWND hwnd ・・・リストビューのウィンドウハンドルを指定します。
・第2引数 DWORD style・・・新しいスタイルを指定します。
では、以下に1行選択を可能にする例を書きます。
例)HWND hList;
DWORD dwStyle;
hList = GetDlgItem(hWnd, リストビューID);
dwStyle = ListView_GetExtendedListViewStyle(hList);
dwStyle |= LVS_EX_FULLROWSELECT;
ListView_SetExtendedListViewStyle(hList, dwStyle);
lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvcol.fmt = LVCFMT_LEFT;
lvcol.cx = 150;
lvcol.pszText = "列1";
lvcol.iSubItem = 0;
ListView_InsertColumn(hList, 0, &lvcol);
lvcol.cx = 200;
lvcol.pszText = "列2";
lvcol.iSubItem = 1;
ListView_InsertColumn(hList, 1, &lvcol);
item.mask = LVIF_TEXT;
item.pszText = "1行目1カラム目";
item.iItem = 0;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "1行目2カラム目";
item.iItem = 0;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目1カラム目";
item.iItem = 1;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目2カラム目";
item.iItem = 1;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
1行選択が出来るようになったのリストビューは、こんな感じです。
(5)グリッド線を入れる(LVS_EX_GRIDLINES)
リストビューに、グリッド線を入れる方法は、(4)の方法と同じで
、ListView_GetExtendedListViewStyleマクロと
ListView_SetExtendedListViewStyleマクロを使用します。
ですので、マクロ引数の説明は省きます。
では、以下に1行選択を可能にし、グリッド線を入れる例を書きます。
例)HWND hList;
DWORD dwStyle;
hList = GetDlgItem(hWnd, リストビューID);
dwStyle = ListView_GetExtendedListViewStyle(hList);
dwStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
ListView_SetExtendedListViewStyle(hList, dwStyle);
lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvcol.fmt = LVCFMT_LEFT;
lvcol.cx = 150;
lvcol.pszText = "列1";
lvcol.iSubItem = 0;
ListView_InsertColumn(hList, 0, &lvcol);
lvcol.cx = 200;
lvcol.pszText = "列2";
lvcol.iSubItem = 1;
ListView_InsertColumn(hList, 1, &lvcol);
item.mask = LVIF_TEXT;
item.pszText = "1行目1カラム目";
item.iItem = 0;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "1行目2カラム目";
item.iItem = 0;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目1カラム目";
item.iItem = 1;
item.iSubItem = 0;
ListView_InsertItem(hList, &item);
item.mask = LVIF_TEXT;
item.pszText = "2行目2カラム目";
item.iItem = 1;
item.iSubItem = 1;
ListView_SetItem(hList, &item);
1行選択が可能になり、グリッド線を入れたリストビューは、こんな感じです。
(6)ダブルクリックイベント(NM_DBLCLK)
リストビューで、ダブルクリックイベントを知るためには、
WM_NOTIFYメッセージ内でNM_DBLCLKを判別する必要があります。
NM_DBLCLKを判別するには、lParamからNMHDR情報を取り出し、
通知メッセージに関する情報を判定する必要があります。
以下に、LPNMHDR構造体の説明を書きます。
<LPNMHDR構造体>
・HWND hwndFrom・・・コントロールのハンドル示します。
・UINT idFrom ・・・コントロールIDを示します。
・UINT code ・・・通知コードを示します。
では、この構造体を利用し、ダブルクリックイベントを知る例を書きます。
下記の例は、ウィンドウプロシージャ内の例です。
例)LPNMHDR lpnmhdr;
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_DBLCLK:
MessageBox(hWnd, "DblClick!", "Message", MB_OK);
break;
}
}
ダブルクリックをしたリストビューは、こんな感じです。
(7)選択中の行を知る(ListView_GetNextItem)
リストビューで、今選択されている行を知るためには、
ListView_GetNextItemマクロを使用します。
以下に、マクロ引数の説明を書きます。
戻り値が-1の場合は、選択されていないことを意味します。
<ListView_GetNextItemマクロ>
・第1引数 HWND hwnd ・・・リストビューのウィンドウハンドルを指定します。
・第2引数 int iStart・・・検索を開始する位置を指定します。
・第3引数 UINT flags ・・・iStartにおいて指定された関係を指定します。
では、以下に1行目を選択後、ダブルクリックでメッセージ表示する例を書きます。
例)HWND hList;
LPNMHDR lpnmhdr;
int index;
char szMsg[16];
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_DBLCLK:
hList = GetDlgItem(hWnd, リストビューID);
index = ListView_GetNextItem(hList, -1, LVNI_SELECTED);
if( index == -1 ){
return;
}
wsprintf(szMsg, "%d行目DblClick!", (index + 1));
MessageBox(hWnd, szMsg, "Message", MB_OK);
break;
}
}
ダブルクリックをしたリストビューは、こんな感じです。
(8)指定セルのデータを取得(ListView_GetItemText)
リストビューで、指定セルのデータを取得するには、
ListView_GetItemTextマクロを使用します。
以下に、マクロ引数の説明を書きます。
<ListView_GetItemTextマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
・第2引数 int iItem
・・・取得したい行を指定します。
・第3引数 int iSubItem
・・・取得したい列を指定します。
・第4引数 LPSTR pszText
・・・取得する項目またはサブアイテムの
バッファへのポインタを指定します。
・第5引数 int cchTextMax
・・・バッファサイズを指定します。
では、以下にダブルクリックで、2行目の列1に欠かれている情報を
取得する例を書きます。
例)HWND hList;
LPNMHDR lpnmhdr;
int index;
char szMsg[32];
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_DBLCLK:
hList = GetDlgItem(hWnd, リストビューID);
ListView_GetItemText(hList, 1, 0, szMsg, sizeof(szMsg));
MessageBox(hWnd, szMsg, "Message", MB_OK);
break;
}
}
ダブルクリックをしたリストビューは、こんな感じです。
(9)全項目数を知る(ListView_GetItemCount)
リストビューで、表示中の全項目数を取得するには、
ListView_GetItemTextマクロを使用します。
以下に、マクロ引数の説明を書きます。
<ListView_GetItemCountマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
では、以下にダブルクリックで、全項目数を取得する例を書きます。
例)HWND hList;
LPNMHDR lpnmhdr;
int cnt;
char szMsg[32];
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_DBLCLK:
hList = GetDlgItem(hWnd, リストビューID);
cnt = ListView_GetItemCount(hList);
wsprintf(szMsg, "全項目数:%d", cnt);
MessageBox(hWnd, szMsg, "Message", MB_OK);
break;
}
}
ダブルクリックをしたリストビューは、こんな感じです。
(10)指定セルのデータを書き換え(ListView_SetItemText)
リストビューで、指定セルのデータを書き換えるには、
ListView_SetItemTextマクロを使用します。
以下に、マクロ引数の説明を書きます。
<ListView_SetItemTextマクロ>
・第1引数 HWND hwnd
・・・リストビューのウィンドウハンドルを指定します。
・第2引数 int iItem
・・・取得したい行を指定します。
・第3引数 int iSubItem
・・・取得したい列を指定します。
・第4引数 LPSTR pszText
・・・取得する項目またはサブアイテムのバッファへの
ポインタを指定します。
では、以下にダブルクリックで、2行目の列1の情報を
書き換える例を書きます。
例)HWND hList;
LPNMHDR lpnmhdr;
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_DBLCLK:
hList = GetDlgItem(hWnd, リストビューID);
ListView_SetItemText(hList, 1, 0, "書き換え後");
break;
}
}
ダブルクリックをしたリストビューは、こんな感じです。
(11)指定行の背景色変更(NM_CUSTOMDRAW)
リストビューで、指定行の背景色を変更するには、カスタムドローを行います。
カスタムドローは、ダブルクリックの取得で説明した時と同じで、
WM_NOTIFYメッセージ内でNM_CUSTOMDRAWを判別します。
更に、リストビュー用のカスタムドロー構造体で、ステージ毎の処理を行います。
今回使用するステージは、以下の2つです。
・CDDS_PREPAINT ・・・描画前通知
・CDDS_ITEMPREPAINT・・・項目毎の描画前通知
使用しないステージの場合は、CDRF_DODEFAULTを戻り値としてリターンします。
これは、コントロールに描画を任すをことを意味します。
このステージを処理した後は、処理したことを通知する必要あるのですが、
ここの例で使用しているのはダイアログである為、通知を返せません。
ですので、SetWindowLong関数を使用して返します。
以下に、NMLVCUSTOMDRAW構造体の説明を書きます。
<NMLVCUSTOMDRAW構造体>
・NMHDR hdr
・・・NMHDR構造体を表します。
・DWORD dwDrawStage
・・・現在の描画ステージを表します。
・HDC hdc
・・・コントロールのデバイスコンテキストハンドルを表します。
・RECT rc
・・・描画されようとしている領域のRECT構造体を表します。
・DWORD dwItemSpec
・・・アイテム番号を表します。
・UINT uItemState
・・・現在のアイテムの状態を表します。
・LPARAM lItemlParam
・・・アプリケーション定義のデータを表します。
では、以下に背景色をグレーに変更する例を書きます。
例)HWND hList;
LPNMHDR lpnmhdr;
LPNMLVCUSTOMDRAW lplvcd;
case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lp;
if( lpnmhdr->hwndFrom == GetDlgItem(hWnd, リストビューのID) ){
switch( lpnmhdr->code ){
case NM_CUSTOMDRAW:
lplvcd = (LPNMLVCUSTOMDRAW)lp;
if( lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT ){
SetWindowLong( hWnd, DWL_MSGRESULT,
(long)CDRF_NOTIFYITEMDRAW );
return( TRUE );
}
if( lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT ){
lplvcd->clrTextBk = RGB(0xCC, 0xCC, 0xCC);
SetWindowLong( hWnd, DWL_MSGRESULT,
(long)CDRF_NEWFONT);
return( TRUE );
}
return( CDRF_DODEFAULT );
背景色を変更したリストビューは、こんな感じです。
<質問・要望など>
上記内容に対しての質問、要望などを、是非お聞かせ下さい。
以下のメールフォームか、掲示板へ書き込みをお願いします。
メール送信フォーム
掲示板
|