|
|
|
|
|
|
|
|
|
|
TREE VIEW |
|
- LEE DO HYEON |
이 도 현
|
목 차 |
|
1 |
트리뷰란? |
|
1 |
|
| |||
|
2 |
STYLE |
|
1 |
|
| |||
|
3 |
메시지 |
|
2 |
|
| |||
|
4 |
통지 메시지 |
|
4 |
|
| |||
|
5 |
TVINSERTSTRUCT |
|
5 |
|
| |||
|
6 |
흐름 |
|
6 |
|
| |||
|
7 |
예제 |
|
7 |
|
|
1. About Tree View
왼쪽에 있는 디렉토리 트리가 대표적인 예다.
사용자의 하드 디스크의 모든 서브 디렉토리와 네트워크 자원까지
한눈에 체계적으로 보여준다.
트리를 구성하는 각 항목을 노드라고 하며 텍스트를 나타내는 레이블과 항목의 종류를 나타내는 비트맵으로 구성되어있다.
항목을 더블 클릭하거나 항목 옆의 +,- 버튼을 눌러 세부항목을 확장하거나 축소할 수 있다.
2. Style
- TVS_HASBUTTONS
자식 항목을 가진 부모 항목 옆에 +, - 버튼을 표시한다.
+ 버튼을 누르면 항목이 확장되어 자식 항목이 펼쳐지며, - 버튼을 누르면 항목이 축소된다.
- TVS_HASBUTTONS
항목간의 계층구조를 좀더 명확히 보이기 위해 점선으로 항목간을 연결하여 표시한다.
- TVS_LINESATROOT
사용자가 항목의 텍스트를 직접 수정할 수 있도록 한다.
- TVS_DISABLEDRAGDROP
스타일의 이름대로 항목을 드래그를 하지 못하게 한다.
이 스타일이 설정되면 TVN_BEGINDRAG 통지 메시지가 전달되지 않는다.
- TVS_SHOWSELALWAYS
트리뷰가 포커스를 가지지 않은 상태에서도 선택된 항목이 반전된 상태로 남는다.
- TVS_TRACKSELECT
한 번 클릭으로 항목을 선택함과 동시에 확장하며, 비 선택된 항목은 자동 축소한다.
- TVS_CHECKBOXES
항목 옆에 체크 박스를 보여준다. 상태 이미지 0은 체크된 모양, 1은 체크되지 않은 모양이다.
3. 메시지
- TVM_CREATEDRAGIMAGE
이미지 리스트를 만들고 lParam 으로 지정한 항목의 드래그 비트맵을 만들어 이미지 리스트에 포함시킨다.
리턴 값은 이미지 리스트의 핸들이다.
- TVM_DELETEITEM
lParam으로 지정한 항목을 삭제한다.
lParam이 TVI_ROOT면 트리의 모든 항목이 삭제된다.
- TVM_EDITLABEL
lParam으로 지정한 항목을 즉시 편집한다.
이 메시지 후에 곧바로 TVN_BEGINLABELEDIT 통지 메시지가 전달된다.
- TVM_ENDEDITLABELNOW
편집중인 항목 편집을 중단한다. wParam이 TRUE이면 편집동작은 취소되며, FALSE면 편집동작 저장 후 종료한다.
- TVM_EXPAND
lParam으로 전달된 항목을 확장하거나 축소한다.
이때 wParam은 다음 중 하나의 플래그가 된다.
→ TVE_COLLAPSE: 축소한다.
→ TVE_COLLAPSERESET: 축소함과 동시에 차일드를 파괴한다.
→ TVE_EXPAND: 확장한다.
→ TVE_TOGGLE: 확장되어 있으면 축소하고 축소되어 있으면 확장한다.
- TVM_GETCOUNT
항목의 개수를 구한다.(총 노드의 개수)
- TVM_GETEDITCONTROL
항목 편집에 사용되는 에디트 컨트롤의 핸들을 구한다.
- TVM_GETINDENT
인덴트 값을 구한다.
- TVM_GETIMAGELIST
트리 컨트롤과 연결된 이미지 리스트의 핸들을 구한다.
wParam은 구하고자 하는 이미지 리스트의 종류를 지정한다.
TVSIL_NORMAL, TVSIL_STATE 중 하나이다.
- TVM_GETISEARCHSTRING
사용자가 키보드로 원하는 항목을 찾아갈 때 사용하는 점진적 검색 문자열을 구한다.
lParam으로 리턴값을 돌려받기 위한 버퍼의 포인터를 넘겨준다.
- TVM_GETITEM
특정 항목을 찾는다. 찾고자 하는 항목의 정보를 TVITEM 구조체의 hItem 멤버에 대입한 후
이 구조체를 lParam으로 넘기면 구조체에 항목의 정보를 채워준다.
이때 채워지는 정보는 mask 멤버가 지정하는 값에 한해서 채워진다.
- TVM_GETTIEMRECT
항목이 차지하고 있는 사각영역을 구한다.
lParam으로 RECT 구조체를 넘기면 이 구조체에 사각영역을 채운다.
wParam이 TRUE이면 문자열 영역에 대해서만 사각영역이 구해지며, FALSE이면 선을 포함한 영역까지 다 구한다.
항목이 보이면 TRUE를 리턴하며, 아닐 시 FALSE를 리턴한다.
- TVM_GETNEXTTIEM
보이는 항목의 개수를 구한다.
단, 이 개수는 트리 컨트롤의 높이를 단순히 항목 높이로 나눈 것이므로 실제로 리턴되는
값은 층 항목보다 작을 수도 있다.
- TVM_HITTEST
특정한 한 점이 트리 컨트롤의 어디쯤인가를 조사한다.
- TVM_INSERTITEM
lParam으로 전달되는 TV_INSERTSTRUCT 구조체의 정보를 참조하여 항목을 추가한다.
- TVM_SELECTITEM
lParam으로 지정한 항목을 선택하거나 보이게 하거나 드롭 타겟으로 그린다.
- TVM_SETIMAGELIST
트리 컨트롤과 연결될 이미지 리스트를 지정한다.
lParam으로 이미지 리스트의 핸들을 주며 wParam으로 이미지 리스트의 종류를 지정한다.
- TVM_SETINDENT
자식 항목과 부모 항목의 가로 좌표 차이인 인덴트 값을 wParam으로 지정한다.
- TVM_SETITEM
항목의 속성을 설정한다. TVITEM 구조체를 작성한 후 lParam으로 전달 한다.
- TVM_SORTCHILDREN
lParam으로 지정한 항목의 자식 항목들을 정렬한다.
wParam을 반드시 0(NULL)을 주어야 한다.
- TVM_SORTCHILDRENCB
프로그램이 정의한 콜백 함수를 사용하여 트리의 항목들을 정렬한다.
lParam으로 TV_SORTCB 구조체를 전달한다.
4. 통지 메시지
- TVN_BEGINDRAG
왼쪽 마우스 버튼으로 항목을 드래그하기 시작할 때 발생한다.
- TVN_BEGINLABELEDIT
레이블을 편집할 때 발생한다.
- TVN_DELETEITEM
한 항목이 삭제될 때 발생한다.
- TVN_ENDLABELEDIT
레이블 편집이 완료되었을 때 발생한다.
- TVN_GETDISPINFO
항목의 출력이나 정렬을 위한 정보를 부모 윈도우에게 요청한다.
- TVN_ITEMEXPANDED
트리가 확장 또는 축소되었을 때 발생한다.
- TVN_ITEMEXPANDING
트리가 확장 또는 축소되고 있을 때 발생한다.
- TVN_KEYDOWN
트리 컨트롤이 포커스를 가지고 있는 상태에서 키보드 입력이 되었을 때 발생한다.
- TVN_SELCHANGED
사용자가 다른 항목을 선택했을 때 발생한다.
- TVN_SELCHANGING
사용자가 다른 항목을 선택하려고 할 때 발생한다.
- TVN_SETDISPINFO
부모 윈도우가 정렬이나 출력을 위해 유지하고 있는 항목의 정보가 갱신되어야 함을
알린다.
5. TVINSERTSTRUCT 구조체
TVINSERTSTRUCT 구조체는 항목을 추가할 때 TVN_INSERTITEM 메시지를
보내는데 이 메시지의 lParam으로 추가하고자 하는 항목의 위치와 속성들을
가지는 TVINSERTSTRUCT 구조체의 포인터를 전달한다.
원형은 아래와 같다.
typedef struct tag TVINSERTSTRUCT
{
HTREEITEM hParent; //트리의 부모 핸들값. ROOT라면 NULL
HTREEITEM hInsertAfter //추가될 항목은 어느 방식으로 추가될지 결정한다.
TVITEMEX itemex; //실제 추가되는 항목에 대한 정보를 가지는 TVITEM or TVITEMEX 구조체
}TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;
hInsertAfter에 올수 있는 인자 3가지
- TVI_FIRST : 제일 첫 위치에 삽입한다.
- TVI_SORT : 알파벳 순으로 정렬한 위치에 삽입한다.
- TVI_LAST : 제일 마지막 위치에 삽입한다.
- TVITEM / TVITEMEX 구조체
typedef struct tag TVITEMEX
{
UINT mask;
HTREEITEM hItem;
UINT state;
UINT stateMask;
LPSTR psztext;
int cchTextMax;
int iImage;
int iSelectedImage;
int cchildren;
LPARAM lParam;
int iIntegral;
} TVITEMEX, FAR *LPTVITEMEX;
- mask
TVITEMEX 구조체의 멤버 중 어느 멤버가 유효한 값을 가지는지 확인한다.
- state, stateMask
state는 항목의 현재 상태를 지정하며 stateMask는 어떤 상태가 가능한가를 지정한다.
- pszText
항목의 실제 내용이 되는 문자열이다.
- cchTextMax
pszText의 길이를 지정한다.
- iImage
항목의 왼쪽에 나타날 이미지의 번호를 지정하며, 이미지 리스트 내의 인덱스 값을 지정한다.
- iSelectedImage
항목이 선택되었을 때 나타날 이미지의 번호를 지정하며, 이미지 리스트 내의 인덱스 값을 지정한다.
- children
이 항목이 자식 항목을 가지고 있는지 조사한다.
0이면 자식항목이 없는 것이고, 1이면 하나 이상의 항목이 있다는 뜻이다.
6. 흐름
7. 예제
- 실습
그림과 같이 ROOT는 선문대학교 원화관이 있다.
그 상태에서 자식 노드를 삽입, 삭제 할 수 있는 프로그램을 만들어 보자.
<실습 완성 화면>
부가 설명은 코드에 있는 tvParam 구조체를 사용하여 lParam으로 값을
넘겨 사용한다.
- 코드 (TreeView.h)
#include <windows.h>
#include "resource.h"
#include <commctrl.h>
HWND hTree; //전역으로사용될TreeView의핸들값..
//TreeView lParam으로사용될부분이다.
struct tvParam{
TCHAR tCaption[20]; //20글자까지저장한다.
};
//더많은정보를넣을수있지만그냥부가설명용으로20글자만넘긴다.
//꼭구조체로선언할필요는전혀없다.
//만들기편하도록임의적으로틀을만드는것이좋다.
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);
void ExitProc(HWND hDlg);
void OnNotify(HWND hDlg,LPNMHDR hdr,LPNMTREEVIEW ntv);
void OnInit(HWND hDlg);
void OnCommand(HWND hDlg, WORD cid);
void Change_TreeViewItem(HWND hDlg,LPNMTREEVIEW ntv); //트리뷰의아이템이바뀌었을때
void Add_TreeViewItem(HWND hDlg); //트리뷰아이템추가
void Delete_TreeViewItem(HWND hDlg); //트리뷰해당아이템삭제
- 코드 (TreeView.cpp)
#include "TreeView.h"
void Add_TreeViewItem(HWND hDlg)
{
TCHAR cTitle[20]; //이름
TCHAR cCaption[20]; //부가설명
GetDlgItemText(hDlg,IDC_NAME,cTitle,20);
SetDlgItemText(hDlg,IDC_NAME,TEXT(""));
GetDlgItemText(hDlg,IDC_CAPTION,cCaption,20);
SetDlgItemText(hDlg,IDC_CAPTION,TEXT(""));
HTREEITEM hNow; //현재TreeView내의선택된위치
TVINSERTSTRUCT TI; //TreeView 구조체선언
tvParam *tParam = new tvParam; //lParam으로넘길구조체생성
lstrcpy(tParam->tCaption,cCaption); //가져온정보를사용자정의구조체에넣는다.
hNow = TreeView_GetSelection(hTree);
TI.hParent = hNow; //부모가될현재객체를얻어옵니다.
TI.hInsertAfter = TVI_LAST;
TI.item.pszText = cTitle;
TI.item.mask = TVIF_TEXT | TVIF_PARAM;//mask에는사용될속성을정의합니다.
//lParam에는tParam을넘겨줘야한다.
TI.item.lParam = (LPARAM)tParam; //형변환으로넘겨주기.
//이제구조체정보를입력했으므로, 실질적추가를해줍니다.
TreeView_InsertItem(hTree,&TI);
//추가를한후에부모노드를확장하여추가한결과를표시해줍니다..
TreeView_Expand(hTree,hNow,TVE_EXPAND);
}
void Change_TreeViewItem(HWND hDlg,LPNMTREEVIEW ntv)
{
TVITEM Ti; //항목에대한정보를갖을TVITEM을선언.
tvParam *tParam; //lParam으로넘어올정보
TCHAR cTitle[20]; //pszText에대입될정보
Ti.mask = TVIF_TEXT | TVIF_PARAM;
Ti.hItem = ntv->itemNew.hItem; //넘어온ntv의정보를통하여아이템을얻어옴
Ti.pszText = cTitle;
Ti.cchTextMax = 20;
TreeView_GetItem(hTree,&Ti); //정보를가지고온다.
tParam = (tvParam*)Ti.lParam; //tParam에가져온lParam정보를대입한다.
//SetDlgItemText를통하여IDC_NODE와IDC_INFO를갱신한다.
SetDlgItemText(hDlg,IDC_NODE,cTitle);
SetDlgItemText(hDlg,IDC_INFO,tParam->tCaption);
}
void Delete_TreeViewItem(HWND hDlg)
{
HTREEITEM hNow; //현재TreeView내의선택된위치
//현재클릭된정보를가져온다. hNow에정보저장.
hNow = TreeView_GetSelection(hTree);
if(hNow == TreeView_GetRoot(hTree)){ //루트일경우삭제하지않는다.
MessageBox(hDlg,TEXT("루트는삭제불가!"),TEXT("경고임ㅎ"),MB_OK);
return;
}
//삭제'_';
TreeView_DeleteItem(hTree,hNow);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShowCmd)
{
DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DlgProc);
return 0;
}
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
case WM_INITDIALOG: OnInit(hDlg); return TRUE;
case WM_COMMAND: OnCommand(hDlg, LOWORD(wParam)); return TRUE;
case WM_NOTIFY:
OnNotify(hDlg,(LPNMHDR)lParam,(LPNMTREEVIEW)lParam); return TRUE;
}
return FALSE;
}
void OnNotify(HWND hDlg,LPNMHDR hdr,LPNMTREEVIEW ntv)
{
if(hdr->hwndFrom == GetDlgItem(hDlg,IDC_TREE1))
{
if(hdr->code == TVN_SELCHANGED)
//TVN_SELCHANGED : 사용자가다른항목을선택했을때발생.
{
Change_TreeViewItem(hDlg,ntv);
}
}
}
void OnInit(HWND hDlg)
{
//최초의부모노드를만들어주기로한다.....
hTree = GetDlgItem(hDlg, IDC_TREE1);
TCHAR cTitle[20] = TEXT("선문대학교원화관");
TCHAR cCaption[20] = TEXT("부가설명이지요");
TVINSERTSTRUCT TI; //트리뷰구조체를사용한다.
tvParam *tParam = new tvParam; //lParam에 넘길 부가설명을 담당할 구조체
TI.hParent = NULL; //부모는부모가없음.
TI.hInsertAfter=TVI_LAST; //마지막에넣던첫번째에넣던상관없다. 인자아무거나..
TI.item.mask=TVIF_TEXT |TVIF_PARAM; // 아이템과파람만넘기도록한다.
TI.item.pszText = cTitle; // 값을넘기고..
lstrcpy(tParam->tCaption,cCaption);
TI.item.lParam = (LPARAM)tParam;
TreeView_InsertItem(hTree,&TI);
TreeView_Expand(hTree,NULL,TVE_EXPAND);
SetDlgItemText(hDlg,IDC_NODE,cTitle);
TreeView_Select(hTree,TreeView_GetRoot(hTree),TVGN_CARET); //강제로Root를선택
}
void OnCommand(HWND hDlg, WORD cid)
{
switch(cid)
{
case IDCANCEL: ExitProc(hDlg); break;
case ID_OK: Add_TreeViewItem(hDlg); break;
case ID_DEL: Delete_TreeViewItem(hDlg); break;
}
}
void ExitProc(HWND hDlg)
{
EndDialog(hDlg, 0);
}
- 간략학 코드 설명
첫 실행시(Dialog Init시, ROOT로 선문대학교원화관 노드를 생성합니다.
TreeView안의 Node를 클릭 시 현재 Node의 Title과 lParam에 들어있는 tvParam을
불러와서 부가설명에 들어있는 내용을 Static Text Window에 출력합니다.
추가를 하게 되면 Add_TreeViewItem() 함수를 이용하여 TreeView안의 현재 선택된 아이템의
정보를 불러와 그 아이템을 부모로 지정하여 삽입하게 됩니다.
통지 메시지는 WM_NOTIFY로 전달되며, 노드가 선택되면 TVN_SELCHANGED 통지 메시지를
사용하여 선택된 노드의 정보를 가져옵니다.
삭제를 하게 되면 TreeView안의 현재 선택된 아이템을 삭제하게 됩니다.
삭제되는 아이템의 자식들 또한 같이 삭제됩니다.