EternalWindows
ツリービュー / イメージリストの設定

ツリービューの各アイテムにはそのアイテムの名前を示すテキストが表示されますが、 この横にはアイコンを表示することが可能になっています。 これを行うには、TreeView_SetImageListでイメージリストを設定します。

HIMAGELIST TreeView_SetImageList(
  HWND hwndTV,
  HIMAGELIST himl,
  INT iImage
);

hwndTVは、ツリービューのハンドルを指定します。 himlは、イメージリストのハンドルを指定します。 iImageは、イメージリストのタイプを指定します。 通常は、TVSIL_NORMALを指定します。

今回のプログラムは、ツリービューにイメージリストを設定します。 作成するツリーは、カレントディレクトリに存在するファイル群を基にしています。

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

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

void InsertTreeItem(HWND hwndTreeView);
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 hwndTreeView = NULL;
	
	switch (uMsg) {
		
	case WM_CREATE: {
		HIMAGELIST           himl;
		SHFILEINFO           fileInfo;
		INITCOMMONCONTROLSEX ic;
		
		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_TREEVIEW_CLASSES;
		InitCommonControlsEx(&ic);
		
		hwndTreeView = CreateWindowEx(0, WC_TREEVIEW, TEXT(""), WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		
		himl = (HIMAGELIST)SHGetFileInfo((LPCTSTR)TEXT("C:\\"), 0, &fileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
		TreeView_SetImageList(hwndTreeView, himl, TVSIL_NORMAL);

		InsertTreeItem(hwndTreeView);

		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(hwndTreeView, 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 InsertTreeItem(HWND hwndTreeView)
{
	TCHAR           szDirectoryName[256];
	HANDLE          hFindFile;
	WIN32_FIND_DATA findData;
	SHFILEINFO      fileInfo;
	TVINSERTSTRUCT  is;
	
	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);
			is.item.iImage = fileInfo.iIcon;
			
			SHGetFileInfo(findData.cFileName, 0, &fileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_OPENICON);
			is.item.iSelectedImage = fileInfo.iIcon;
			
			is.hParent      = TVI_ROOT;
			is.item.mask    = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
			is.item.pszText = findData.cFileName;
			TreeView_InsertItem(hwndTreeView, &is);
		}

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

今回はカレントディレクトリに存在するファイルの名前を持ったアイテムを作成しますから、 必要なアイコンは各種ファイルのアイコンになります。 これはシステムイメージリストと呼ばれる特別なイメージリストに格納されており、 SHGetFileInfoにSHGFI_SYSICONINDEXを指定することで取得できます。 SHGFI_SMALLICONは小さいアイコンをイメージリストに格納することを意味しています。 取得したシステムイメージリストはTreeView_SetImageListに指定します。

今回のInsertTreeItemでは、カレントディレクトリのファイルを走査しながらアイテムの追加を行っています。

void InsertTreeItem(HWND hwndTreeView)
{
	TCHAR           szDirectoryName[256];
	HANDLE          hFindFile;
	WIN32_FIND_DATA findData;
	SHFILEINFO      fileInfo;
	TVINSERTSTRUCT  is;
	
	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);
			is.item.iImage = fileInfo.iIcon;
			
			SHGetFileInfo(findData.cFileName, 0, &fileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_OPENICON);
			is.item.iSelectedImage = fileInfo.iIcon;
			
			is.hParent      = TVI_ROOT;
			is.item.mask    = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
			is.item.pszText = findData.cFileName;
			TreeView_InsertItem(hwndTreeView, &is);
		}

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

GetCurrentDirectoryでカレントディレクトリのパスを取得したら、\*という文字列を終端に連結します。 これは、FindFirstFileを呼び出すために必要な作業です。 この関数はファイルを列挙するためのハンドルを返すようになっており、 これをFindNextFileに指定することで指定ディレクトリのファイルを走査できるようになります。 ただし、この列挙されるファイルには上位のディレクトリと現在のディレクトリも含まれるため、 if文によってこれらは考慮しないようにしています。 アイテムの追加処理については、イメージリストを設定しているという関係上、 maskにTVIF_IMAGEとTVIF_SELECTEDIMAGEを指定しています。 これにより、アイコンのインデックスを表すiImageと、選択されたアイコンのインデックスを表すiSelectedImageが考慮されるようになります。 後者のアイコンのインデックスを取得するには、SHGetFileInfoにSHGFI_OPENICON指定することになります。


戻る