탐색기의 왼쪽 폴더 리스트처럼 폴더 트리를 만드는 방법.
MFC의 CTreeView로 작성 함. (자료찾기 힘들다. VC++ 책들은 줄줄이 절판중..)
결과 화면
"CTreeView" .h 헤더에 추가한 멤버 함수
bool composeTreeList(void);
int GetItemIcon(LPITEMIDLIST lpi, UINT flags);
static int CALLBACK CompareItemForSorting(LPARAM, LPARAM, LPARAM);
"CTreeView" .cpp 소스
void CFolderListView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
// TODO: You may populate your TreeView with items by directly accessing
// its tree control through a call to GetTreeCtrl().
//폴더 정보 출력
composeTreeList();
//루트 트리 펼침
HTREEITEM hRootItem = treeCtrl.GetRootItem();
treeCtrl.Expand(hRootItem, TVE_EXPAND); //펼침
//특정 함수로 정렬
TV_SORTCB tvscb;
tvscb.hParent = hRootItem;
tvscb.lParam = 0;
tvscb.lpfnCompare = CompareItemForSorting; //아이템 정렬을 위한 함수
CTreeCtrl& treeCtrl = GetTreeCtrl();
treeCtrl.SortChildrenCB(&tvscb);
}
//TreeList 를 구성함
bool CFolderListView::buildFolderList(void)
{
bool bRet = true;;
HRESULT hr;
HTREEITEM hPrevItem = NULL;
LPSHELLFOLDER lpsf = NULL;
//트리 초기화 (아이템 모두 삭제)
CTreeCtrl& treeCtrl = GetTreeCtrl();
treeCtrl.DeleteAllItems();
//root 아이템으로 바탕화면 추가
CString strDesktop = _T("바탕 화면");
LPITEMIDLIST pDesktopIDList = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pDesktopIDList);
TV_INSERTSTRUCT tviRoot;
tviRoot.hParent = TVI_ROOT; //root 레벨로 추가함
tviRoot.hInsertAfter = TVI_FIRST; //맨 위에 추가
tviRoot.item.pszText = strDesktop.GetBuffer(); //이름
tviRoot.item.cchTextMax = strDesktop.GetLength(); //최대길이
tviRoot.item.iImage = GetItemIcon(pDesktopIDList, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON); //아이콘
tviRoot.item.iSelectedImage = GetItemIcon(pDesktopIDList, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON); //선택시 아이콘
tviRoot.item.lParam = (LPARAM)tviRoot.item.pszText;
tviRoot.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; //사용할 멤버변수
HTREEITEM hRootItem = treeCtrl.InsertItem(&tviRoot);
try
{
//shell 메모리 할당
LPMALLOC lpMalloc = NULL;
if (FAILED(CoGetMalloc(1, &lpMalloc)))
throw CString(_T("CoGetMalloc error"));
//데스크탑 폴더에 대한 인터페이스 획득
hr = SHGetDesktopFolder(&lpsf);
if (FAILED(hr))
throw CString(_T("SHGetDesktopFolder error"));
//아이템 enum 획득
IEnumIDList* pEnumIDList = NULL;
hr = lpsf->EnumObjects(::GetParent(m_hWnd), SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &pEnumIDList);
if (FAILED(hr))
throw CString(_T("lpsf->EnumObjects error"));
LPITEMIDLIST pItemIDList; //아이템을 담을 변수
ULONG ulFetched; //pItemIDList의 길이 정보를 받을 변수
//아이템 enum순회하며 TreeView에 등록 : pItemIDList에 아이템을 담음
while (pEnumIDList->Next(1, &pItemIDList, &ulFetched) == S_OK)
{
//아이템 속성 획득
ULONG attrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER; //획득하고픈 속성 : 하위 폴더 있는지, 폴더 인지
hr = lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST**)&pItemIDList, &attrs); //attrs엔 아이템이 갖고 있는 모든 속성이 세팅됨
if (hr != S_OK)
throw CString(_T("lpsf->GetAttributesOf"));
//속성별 설정
if (attrs & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER)) //하위 폴더가 있거나 폴더인 경우
{
if (attrs & SFGAO_FOLDER) //폴더인 경우
{
//아이템 이름 구하기
STRRET str; //아이템 이름이 담길 구조체
hr = lpsf->GetDisplayNameOf(pItemIDList, SHGDN_NORMAL, &str); //아이템 이름 조회
if (hr != S_OK)
throw CString(_T("lpsf->GetDisplayNameOf error"));
TCHAR displayName[MAX_PATH]; //아이템 이름을 담을 변수
switch (str.uType) //획득한 문자열(폴더이름)에 대한 타입
{
case STRRET_CSTR: //문자열이 cStr 멤버에 담겨있는 경우
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.cStr, strlen(str.cStr), displayName, MAX_PATH);
break;
case STRRET_OFFSET: //문자열의 시작 주소가 별도로 지정된 경우(uOffset멤버변수)
//lstrcpy(displayName, (LPTSTR)pItemIDList + str.uOffset);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)(pItemIDList + str.uOffset), strlen((const char*)pItemIDList + str.uOffset), displayName, MAX_PATH);
break;
case STRRET_WSTR: //문자열이 pOleStr 멤버에 담겨있는 경우 :유니코드환경이면 이것만 사용됨
lstrcpy(displayName, str.pOleStr);
break;
default:
throw CString(_T("lpsf->GetDisplayNameOf error"));
}
//lParam
TCHAR* lParam = (TCHAR*)lpMalloc->Alloc(sizeof(TCHAR) * (lstrlen(displayName) + 1)); //lParam을 위한 메모리 할당
lstrcpy(lParam, displayName); //값 할당
//TreeView에 추가할 아이템의 속성 설정
TV_ITEM tvi;
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN; //사용할 멤버변수 지정
tvi.pszText = displayName; //폴더 이름
tvi.cchTextMax = MAX_PATH; //폴더 이름 최대 길이
tvi.cChildren = (attrs & SFGAO_HASSUBFOLDER) ? 1 : 0; //하위 폴더 존재 여부 설정
tvi.iImage = GetItemIcon(pItemIDList, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON); //아이콘
tvi.iSelectedImage = GetItemIcon(pItemIDList, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON); //펼칠때 아이콘
tvi.lParam = (LPARAM)lParam; //정렬할때 사용하기 위한 lParam
//TreeView에 추가를 위한 변수
TV_INSERTSTRUCT tvins;
tvins.item = tvi; //속성 변수
tvins.hParent = hRootItem; //root 아이템 아래 추가
tvins.hInsertAfter = hPrevItem; //hPrevItem 다음에 추가
//TreeView에 추가
hPrevItem = treeCtrl.InsertItem(&tvins); //다음 item추가를 위해 현재 아이템 저장
}
}
lpMalloc->Free(pItemIDList);
pItemIDList = NULL;
}
}
catch (CString& errorMsg)
{
AfxMessageBox(errorMsg);
bRet = false;
}
if (lpsf != NULL) lpsf->Release();
return bRet;
}
//아이템의 아이콘을 구하기 위한 함수
int CFolderListView::GetItemIcon(LPITEMIDLIST lpi, UINT flags)
{
SHFILEINFO sfi;
SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), flags);
return sfi.iIcon;
}
//아이템 정렬을 위한 compare 함수
int CALLBACK CFolderListView::CompareItemForSorting(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort)
{
/*
CString str1 = (TCHAR*)lparam1;
CString str2 = (TCHAR*)lparam2;
return str1.Compare(str2);
*/
return 0;
}
'C++' 카테고리의 다른 글
[MFC] CDaoDatabase : DAO (Data Access Object) (2) | 2010.12.09 |
---|---|
[MFC] 다른 윈도우 찾기 (0) | 2010.12.09 |
[MFC] 메뉴 제거, 타이틀 제거, 캡션 변경. 창 크기 설정 방법 (0) | 2010.12.09 |
[MFC] splitter UI 바꾸기 (0) | 2010.12.09 |
[MFC] 인터넷 HTML 소스 다운로드 (1) | 2010.12.01 |
윈도우 서비스 (service) (0) | 2010.11.25 |
performance counter (성능 모니터링) (0) | 2010.11.25 |
MiniDump (미니 덤프 생성하기) (0) | 2010.11.13 |