リストビュー


詳細情報の表示

標準のリストボックスは、何らかの情報を列挙する時に便利でした
しかし、アプリケーションが何らかのデータベースを表示する場合
リストボックスは情報を表示するのに十分な能力がないことがわかるでしょう

例えば、ファイルを列挙する時、ファイルのサイズや作成日などを同時に表示したり
さらに、ファイルのアイコンもリストに表示させたい場合
リストボックスにはアイコンを表示する能力も、項目別の表示もサポートしていません

データベースの表示には、やはり行と列にまとめることが望ましく
これを実現するコモンコントロールがリストビューコントロールです

リストビューを作成するには、まず CreateWindowEx() 関数を用い
第二引数に、ウィンドウクラス WC_LISTVIEW を指定します
ウィンドウスタイルには、従来のものと次の固有スタイルを指定できます

定数解説
LVS_ALIGNLEFT 大きいアイコン、小さいアイコン表示で項目が左寄せになる
LVS_ALIGNTOP 大きいアイコン、小さいアイコン表示で項目が上に寄せられる
LVS_AUTOARRANGE 大きいアイコン、小さいアイコン表示で自動的に整列する
LVS_BUTTON 大きいアイコン表示で、項目アイコンをボタン風にする
LVS_EDITLABELS テキストは編集可能である
親ウィンドウが LVN_ENDLABELEDIT 通知を処理しなければならない
LVS_ICON 大きいアイコン表示
LVS_LIST 一覧表示
LVS_NOCOLUMNHEADER 詳細表示で、列見出しが表示されない
LVS_NOLABELWRAP 大きいアイコン表示で項目テキストを1行に表示
LVS_NOSORTHEADER 列見出しをクリックしてもアクションを実行しない
LVS_OWNERDRAWFIXED 詳細表示で、項目をオーナーが描画する
親ウィンドウは WM_DRAWITEM メッセージを受けるようになる
LVS_REPORT 詳細表示
最初の列が常に左寄せにされる
LVS_SHAREIMAGELISTS コントロールが破棄されても
関連付けられているイメージリストを破棄しない
複数のリストビューでイメージリストを共有する時に指定する
LVS_SHOWSELALWAYS フォーカスを失っても、常に選択を表示する
LVS_SINGLESEL 1度に1つの項目のみを選択できる
LVS_SMALLICON 小さいアイコン表示
LVS_SORTASCENDING 項目テキストが昇順になるように、項目を整列する
LVS_SORTDESCENDING 項目テキストが降順になるように、項目を整列する

あとは、CreateWindowEx() で作成したリストビューのハンドルに
マクロを使ってメッセージを送信することで、項目などを追加することができます
カーソルの変更や、スクロールバーなどの基本処理は、全てコントロールが行ってくれます

まず、リストビューにはを作る必要があります
列を作成するには ListView_InsertColumn() マクロを用います

int ListView_InsertColumn(HWND hwnd , int iCol , const LPLVCOLUMN pcol);

hwnd には、リストビューのハンドルを、iCol には追加する列のインデックスを指定します
pcol は、新しい列の情報を格納した LVCOLUMN 構造体へのポインタを指定します
成功すれば新しいインデックスが、失敗すれば -1 が返ります

LVCOLUMN 構造体は次のように定義されています
typedef struct _LVCOLUMN { 
    UINT mask; 
    int fmt; 
    int cx; 
    LPTSTR pszText; 
    int cchTextMax; 
    int iSubItem; 
} LVCOLUMN, FAR *LPLVCOLUMN;
mask には、有効な情報が含まれるメンバを表すフラグを指定します
このフラグによって、この構造体のうち、どのメンバを使用するか指定します
このメンバには、以下の定数を組み合わせて指定することができます

定数解説
LVCF_FMT fmt メンバが有効
LVCF_SUBITEM iSubItem メンバが有効
LVCF_TEXT pszTest メンバが有効
LVCF_WIDTH cs メンバが有効

fmt メンバには、列のは一方法を表す定数を指定します
左寄せを表す LVCFMT_LEFT、右寄せの LVCFMT_RIGHT
センタリングの LVCFMT_CENTER のいずれかの定数を指定します
ただし、最初の列は常に左寄せ LVCFMT_LEFT でなければなりません

cx には、列の幅をピクセル単位で指定します
pszText には、列の見出しを表す文字列へのポインタを指定します
情報を取得する時に構造体が使われるならば、文字列を受けるバッファへのポインタです

cchTextMax は、pszText メンバのバッファのサイズを指定します
列についての情報を受け取るメッセージで、この構造体が使用された時に使われます
列の情報を設定する時であれば、このメンバは無視されます

iSubItem には、列と関連付けられたサブ項目のインデックスを指定します
これは、複数の列を用意し、特定の列に項目を追加する時に指定するインデックスです

列を作成すれば、次に、その列に項目を追加します
項目を追加するには ListView_InsertItem() を使います
このマクロは、新しい行を作るものであり、最初の列にしか項目を追加できません

int ListView_InsertItem(HWND hwnd , const LPLVITEM pitem);

hwnd には、リストビューのハンドルを指定します
pitem は、項目の情報を含む LVITEM 構造体へのポインタを指定します
成功すれば項目のインデックスが、失敗すれば -1 が返ります

LVITEM 構造体は、次のように定義されています
typedef struct _LVITEM { 
    UINT   mask; 
    int    iItem; 
    int    iSubItem; 
    UINT   state; 
    UINT   stateMask; 
    LPTSTR  pszText; 
    int    cchTextMax; 
    int    iImage; 
    LPARAM lParam;
} LVITEM, FAR *LPLVITEM;
mask には、この構造体の使用するメンバを表すフラグを指定します
このメンバには、以下の定数を組み合わせて指定することができます

定数解説
LVIF_DI_SETITEM LVN_GETDISPINFO 通知メッセージでのみ設定可能で
システムが要求された項目情報を、格納し再度尋ねないことを表す
LVIF_IMAGE iImage メンバが有効である
LVIF_PARAM lParam メンバが有効である
LVIF_STATE state メンバが有効である
LVIF_TEXT pszText メンバが有効である

iItem は、項目のインデックスを、iSubItem にはサブ項目のインデックスを指定します
項目のインデックスは、列の上から数えた番号、サブ項目は行の左から数えた番号です

state は項目の現在の状態を表すフラグを
stateMask は項目の有効な状態を表すフラグを指定します

定数解説
LVIS_CUT 切り取りと貼り付け操作に対してマークされる
LVIS_DRAPHILITED 切り取りと貼り付け操作の対象として強調表示される
LVIS_FOCUSED フォーカスをもっている
LVIS_OVERLAYMASK オーバーレイイメージインデックスが含まれているかどうか判定する
LVIS_SELECTED 選択されている
LVIS_STATEIMAGEMASK 状態イメージが関連付けられているかどうか判定する

pszText には、項目のテキストとなる文字列へのポインタを指定します
情報を取得する場合、このポインタは文字列を格納するバッファへのポインタです
ccTextMax は pszText で指定下バッファのサイズを指定します
情報を設定する場合、このメンバは無視されます

iImage には、リストビューに用いるアイコンのインデックスを指定します
このインデックスは、リストビューに関連付けられているイメージリストのインデックスです
lParam は、項目に関連付ける32ビット値を指定できます

この構造体を設定し、ListView_InsertItem() に渡せば、項目が追加されます
これで、列に続いて行を指定することができるようになります
#include <windows.h>
#include <commctrl.h>
#define TITLE TEXT("Kitty on your lap")

LPCTSTR strItem[] = {TEXT("RENA") , TEXT("YUKI") , TEXT("MIMI")};

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	LVCOLUMN col;
	LVITEM item = {0};
	int iCount = 0;
	static HWND hList;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		InitCommonControls();
		hList = CreateWindowEx(0 , WC_LISTVIEW , 0 , 
			WS_CHILD | WS_VISIBLE | LVS_REPORT ,
			0 , 0 , 10 , 10 , hWnd , (HMENU)1 ,
			((LPCREATESTRUCT)lp)->hInstance , NULL);

		col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
		col.fmt = LVCFMT_LEFT;
		col.cx = 100;
		col.pszText = TITLE;
		ListView_InsertColumn(hList , 0 , &col);

		item.mask = LVIF_TEXT;
		for ( ;iCount < 3 ; iCount++) {
			item.pszText = strItem[iCount];
			item.iItem = iCount;
			ListView_InsertItem(hList , &item);
		}
		return 0;
	case WM_SIZE:
		MoveWindow(hList , 0 , 0 , LOWORD(lp) , HIWORD(lp) , FALSE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);
	if (hWnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


このプログラムを実行すれば、上の図のウィンドウが表示されます
1列3行のリストビューで、列の幅は動的に変化させることができます

作成した項目に対する属性情報を追加するには
属性用の列を作成し、ListView_SetItem() マクロで追加します

BOOL ListView_SetItem(HWND hwnd , const LPLVITEM pitem);

hwnd は、リストビューのハンドルを指定します
pitem は、項目の設定する属性情報を含む LVITEM 構造体へのポインタを指定します
基本的なメカニズムは、項目を追加する時とほとんど変わりません
成功すれば TRUE、失敗すれば FALSE が返ります
#include <windows.h>
#include <commctrl.h>
#define TITLE TEXT("Kitty on your lap")

LPTSTR strItem[] = {TEXT("RENA") , TEXT("YUKI") , TEXT("MIMI")};
LPTSTR strAttr[] = {
	TEXT("口が悪くて手が早い、勝手気ままでまさに「猫」") ,
	TEXT("思慮深く、清楚でけなげ") ,
	TEXT("「ごしゅじんさまだ〜いすきっ!」と飛びついてきそうな甘えん坊")
};

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	LVCOLUMN col;
	LVITEM item = {0};
	int iCount = 0;
	static HWND hList;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		InitCommonControls();
		hList = CreateWindowEx(0 , WC_LISTVIEW , 0 , 
			WS_CHILD | WS_VISIBLE | LVS_REPORT ,
			0 , 0 , 10 , 10 , hWnd , (HMENU)1 ,
			((LPCREATESTRUCT)lp)->hInstance , NULL);

		col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
		col.fmt = LVCFMT_LEFT;
		col.cx = 100;
		col.pszText = TEXT("Name");
		col.iSubItem = 0;
		ListView_InsertColumn(hList , 0 , &col);

		col.iSubItem = 1;
		col.pszText = TEXT("Introduction");
		ListView_InsertColumn(hList , 1 , &col);

		item.mask = LVIF_TEXT;
		for ( ;iCount < 3 ; iCount++) {
			item.pszText = strItem[iCount];
			item.iItem = iCount;
			item.iSubItem = 0;
			ListView_InsertItem(hList , &item);

			item.pszText = strAttr[iCount];
			item.iItem = iCount;
			item.iSubItem = 1;
			ListView_SetItem(hList , &item);
		}
		return 0;
	case WM_SIZE:
		MoveWindow(hList , 0 , 0 , LOWORD(lp) , HIWORD(lp) , FALSE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);
	if (hWnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


いかがでしょう、複数の列が作成され、Introduction の列に項目の属性を表示しています
このコントロールを使えば、システムの情報を表示するアプリケーションや
ファイル管理ツールなど、様々なビジネスアプリケーションへの応用も考えられます


アイコンの追加

リストビューの項目にアイコンを用いる場合、イメージリストを用います
そのため、あらかじめイメージリストを用意してください

イメージリストができれば、あとは ListView_SetImageList()
リストビューとイメージリストを関連付けます
そうすれば、項目を追加する時に、インデックスで特定のアイコンを指定することができます
HIMAGELIST ListView_SetImageList(
	HWND hwnd , HIMAGELIST himl , int iImageList
);
hwnd には、リストビューのハンドルを指定します
himl は、リストビューに関連付けるイメージリストのハンドルを指定します

iImageList は、himl で指定するイメージリストのタイプを表すフラグを指定します
この引数には、以下の定数のいずれかを指定できます

定数解説
LVSIL_NORMAL 大きいアイコン
LVSIL_SMALL 小さいアイコン
LVSIL_STATE 状態イメージ

成功すれば、以前関連付けられていたイメージリストのハンドルが
失敗すれば NULL が返ります
#define OEMRESOURCE
#include <windows.h>
#include <commctrl.h>
#define TITLE TEXT("Kitty on your lap")

LPTSTR strItem[] = {TEXT("RENA") , TEXT("YUKI") , TEXT("MIMI")};

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	LVCOLUMN col;
	LVITEM item = {0};
	HIMAGELIST hImg;
	int iCount = 0;
	static HWND hList;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		InitCommonControls();
		hImg = ImageList_Create(16 , 16 , ILC_COLOR4 | ILC_MASK, 1 , 1);
		ImageList_AddIcon(hImg , LoadIcon(NULL , IDI_ASTERISK));

		hList = CreateWindowEx(0 , WC_LISTVIEW , 0 , 
			WS_CHILD | WS_VISIBLE | LVS_REPORT ,
			0 , 0 , 10 , 10 , hWnd , (HMENU)1 ,
			((LPCREATESTRUCT)lp)->hInstance , NULL);

		ListView_SetImageList(hList , hImg , LVSIL_SMALL);

		col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
		col.fmt = LVCFMT_LEFT;
		col.cx = 100;
		col.pszText = TEXT("Name");
		ListView_InsertColumn(hList , 0 , &col);

		item.mask = LVIF_TEXT | LVIF_IMAGE;
		item.iImage = 0;
		for ( ;iCount < 3 ; iCount++) {
			item.pszText = strItem[iCount];
			item.iItem = iCount;
			ListView_InsertItem(hList , &item);
		}
		return 0;
	case WM_SIZE:
		MoveWindow(hList , 0 , 0 , LOWORD(lp) , HIWORD(lp) , FALSE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);
	if (hWnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


このプログラムは、アイコンイメージを持つリストビューを表示します
上の図を見てわかるように、イメージリストに追加した情報アイコンが
リストビューの項目の左側に寄せられて表示されていることが確認できるでしょう


ListView_InsertColumn()

int ListView_InsertColumn(HWND hwnd , int iCol , const LPLVCOLUMN pcol);

リストビューに新しい項目を追加します

hwnd - リストビューのハンドルを指定します
iCol - 追加する列のインデックスを指定します
pcol - 新しい列の情報を格納した LVCOLUMN 構造体へのポインタを指定します

戻り値 - 新しいインデックス、失敗すれば -1

ListView_InsertItem()

int ListView_InsertItem(HWND hwnd , const LPLVITEM pitem);

リストビューに新しい項目を追加します

hwnd - リストビューのハンドルを指定します
pitem - 項目の情報を含む LVITEM 構造体へのポインタを指定します

戻り値 - 項目のインデックス、失敗すれば -1

ListView_SetItem()

BOOL ListView_SetItem(HWND hwnd , const LPLVITEM pitem);

リストビューの項目の属性を設定します

hwnd - リストビューのハンドルを指定します
pitem - 属性情報を含む LVITEM 構造体へのポインタを指定します

戻り値 - 成功すれば TRUE、失敗すれば FALSE

ListView_SetImageList()

HIMAGELIST ListView_SetImageList(
	HWND hwnd , HIMAGELIST himl , int iImageList
);
リストビューにイメージリストを割り当てます

hwnd - リストビューのハンドルを指定します
himl - リストビューに関連付けるイメージリストのハンドルを指定します
iImageList - himl で指定するイメージリストのタイプを表すフラグを指定します

戻り値 - 以前関連付けられていたイメージリストのハンドル、失敗すれば NULL

iImageList には、以下の定数のいずれかを指定することができます

定数解説
LVSIL_NORMAL 大きいアイコン
LVSIL_SMALL 小さいアイコン
LVSIL_STATE 状態イメージ



前のページへ戻る次のページへ