EternalWindows
リストビュー / タイル表示

今回は、リストビューをタイル表示します。 次に、タイル表示の例を示します。

アイコン表示ではアイテムの名前とアイコンを表示するだけでしたが、 タイル表示ではアイテムの説明文も表示することができます。 たとえば上図では、ファイルシステム上におけるファイルサイズを表示しています。

リストビューをタイル表示するには、ListView_SetViewを呼び出します。

int ListView_SetView(
  HWND hwnd,
  DWORD iView
);

hwndは、リストビューのウインドウハンドルを指定します。 iViewは、表示の種類を表す定数を指定します。 LV_VIEW_TILEを指定すればタイル表示になります。 このマクロは、現在の表示形式を別の表示形式に切り替えたい場合にも使用されます。

今回のプログラムは、リストビューをタイル表示します。 StrFormatByteSize64という関数を使用している関係上、 shlwapi.hのインクルードとshlwapi.libへのリンクが必要になります。 バージョン5系列のcomctl32.dllを使用している場合はタイル表示ができないため、 プロジェクトにマニフェストファイルを追加する必要があります。

#include <windows.h>
#include <commctrl.h>
#include <shlwapi.h>

#pragma comment (lib, "comctl32.lib")
#pragma comment (lib, "shlwapi.lib")

void InsertListViewItem(HWND hwndListView);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListView = NULL;
	
	switch (uMsg) {
		
	case WM_CREATE: {
		HIMAGELIST           himl;
		SHFILEINFO           fileInfo;
		INITCOMMONCONTROLSEX ic;
		LVCOLUMN             column;
		
		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_LISTVIEW_CLASSES;
		InitCommonControlsEx(&ic);
		
		hwndListView = CreateWindowEx(0, WC_LISTVIEW, TEXT(""), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		
		himl = (HIMAGELIST)SHGetFileInfo((LPCTSTR)TEXT("C:\\"), 0, &fileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
		ListView_SetImageList(hwndListView, himl, LVSIL_NORMAL);
		
		column.mask = 0;
		ListView_InsertColumn(hwndListView, 0, &column);
		
		column.mask = 0;
		ListView_InsertColumn(hwndListView, 1, &column);
		
		InsertListViewItem(hwndListView);

		ListView_SetView(hwndListView, LV_VIEW_TILE);

		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(hwndListView, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void InsertListViewItem(HWND hwndListView)
{
	int             i = 0;
	TCHAR           szDirectoryName[256];
	TCHAR           szBuf[256];
	HANDLE          hFindFile;
	WIN32_FIND_DATA findData;
	SHFILEINFO      fileInfo;
	LVITEM          item;
	UINT            uSubItems[] = {1};
	
	GetCurrentDirectory(sizeof(szDirectoryName) / sizeof(TCHAR), szDirectoryName);
	lstrcat(szDirectoryName, TEXT("\\*"));

	hFindFile = FindFirstFile(szDirectoryName, &findData);

	do {
		if (lstrcmp(findData.cFileName, TEXT("..")) != 0 && lstrcmp(findData.cFileName, TEXT(".")) != 0) {
			SHGetFileInfo(findData.cFileName, 0, &fileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);
			
			item.mask      = LVIF_TEXT | LVIF_IMAGE | LVIF_COLUMNS;
			item.iItem     = i;
			item.iSubItem  = 0;
			item.pszText   = findData.cFileName;
			item.iImage    = fileInfo.iIcon;
			item.cColumns  = 1;
			item.puColumns = uSubItems;
			ListView_InsertItem(hwndListView, &item);

			StrFormatByteSize64(findData.nFileSizeLow, szBuf, sizeof(szBuf) / sizeof(TCHAR));
			ListView_SetItemText(hwndListView, i, 1, szBuf);

			i++;
		}

	} while(FindNextFile(hFindFile, &findData));
	
	FindClose(hFindFile);
}

タイル表示はアイテムをアイコンとして表示する形式ですが、 ListView_InsertColumnの呼び出しは必須になります。 理由は、これを呼び出さないとListView_SetItemText(及びListView_SetItem)が正しく機能しないからです。 ただし、実際にカラムが表示されるわけではないので、 maskには0を指定して、その他のメンバは初期化していません。 InsertListViewItemでは前節と同じように、カレントディレクトリに存在するファイルの数だけアイテムを追加しますが、 追加に関するコードは前節と異なります。

item.mask      = LVIF_TEXT | LVIF_IMAGE | LVIF_COLUMNS;
item.iItem     = i;
item.iSubItem  = 0;
item.pszText   = findData.cFileName;
item.iImage    = fileInfo.iIcon;
item.cColumns  = 1;
item.puColumns = uSubItems;
ListView_InsertItem(hwndListView, &item);

StrFormatByteSize64(findData.nFileSizeLow, szBuf, sizeof(szBuf) / sizeof(TCHAR));
ListView_SetItemText(hwndListView, i, 1, szBuf);

i++;

maskにLVIF_COLUMNSを指定した場合、puColumnsとcColumnsを初期化することになります。 cColumnsは、puColumnsに指定した配列の要素数を指定します。 puColumnsにはサブアイテムのインデックスを格納した配列を指定することになっており、 今回の場合この配列には1が格納されています。 つまり、1番目のサブアイテムのテキストがアイコンの説明文として表示されます。 StrFormatByteSize64は、第1引数の値をKB単位やMB単位に記述した文字列を返す関数です。 この文字列をListView_SetItemTextでサブアイテムとして設定しているため、 アイコンの説明文にはファイルサイズが表示されることになります。

ListView_SetTileInfoについて

今回はリストビューをタイル表示するために、 アイテムの追加時にサブアイテムのインデックスを指定しましたが、 これはアイテム追加後にListView_SetTileInfoを呼び出すことで行うこともできます。 次に例を示します。

int        i;
int        nCount = ListView_GetItemCount(hwndListView);
UINT       uSubItems[] = {1};
LVTILEINFO tileInfo;

for (i = 0; i < nCount; i++) {
	tileInfo.cbSize    = sizeof(LVTILEINFO);
	tileInfo.iItem     = i;
	tileInfo.cColumns  = 1;
	tileInfo.puColumns = uSubItems;
	tileInfo.piColFmt  = 0;
	ListView_SetTileInfo(hwndListView, &tileInfo);
}

アイテムの数をListView_GetItemCountで取得し、 この数だけListView_SetTileInfoを呼び出しています。 iItemにはアイテムのインデックスを指定し、cColumnsにはpuColumnsの要素数、 uSubItemsにはサブアイテムのインデックスを格納した配列を指定します。



戻る